Entwickler-Ecke
Windows API - TThread(s) durchgehen und prüfen?
fuba - Fr 30.07.10 00:20
Titel: TThread(s) durchgehen und prüfen?
Hi @ all
Meine frage im Detail:
Wie kann ich meine Threads "durchgehen" und prüfen ob diese noch laufen, ohne für jeden Thread eine Variable zu deklarieren?
Wie das ganze mit einem Thread funktioniert is mir klar, aber bei mehreren Threads...
code Hauptform:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TForm1 = class(TForm) ListBox1: TListBox; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private public end;
var Form1: TForm1;
implementation
uses Unit3;
var Thread: TTestThread;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject); var i: integer; begin ListBox1.Clear; for i:=0 to 3 do begin ListBox1.Items.Append('Thread'+IntToStr(i+1)); end; end;
procedure TForm1.Button1Click(Sender: TObject); var aName: string; begin if ListBox1.ItemIndex > -1 then begin aName:=ListBox1.Items[ListBox1.ItemIndex];
Thread := TTestThread.Create(true); with Thread do begin FreeOnTerminate := True; Thread.ThreadName:=aName; Resume; end; end; end;
end. |
code Thread Unit:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
| unit Unit3;
interface
uses Classes, Windows;
type TTestThread = class(TThread) ThreadName: string; private protected procedure Execute; override; end;
implementation
procedure TTestThread.Execute; begin while (not Terminated) do begin sleep(1000); end; end;
end. |
Jedes mal, wenn ich auf Button1 drücke, startet ein neuer Thread, was auch so gewollt ist.
Der Name bzw der Eintrag aus der ListBox wird als aName dem Thread übergeben, sozusagen als Identifizierung.
Aber nun möchte ich per klick auf auf die ListBox prüfen ob Thread1 noch läuft, wenn ja mit klick auf Button1 diesen wieder beenden.
Gibt es eine Möglichkeit alle meine Threads "durchzugehen" und auf aName zu prüfen?
vielen dank für eure hilfe(n)!
elundril - Fr 30.07.10 01:26
Kannst du die referenz nicht in einem array of TTestThread speichern? Hab aber noch nie mit Threads programmiert (in delphi zumindest), insofern is es nur ein vorschlag.
lg elundril
fuba - Fr 30.07.10 02:51
elundril hat folgendes geschrieben : |
Kannst du die referenz nicht in einem array of TTestThread speichern? Hab aber noch nie mit Threads programmiert (in delphi zumindest), insofern is es nur ein vorschlag.
lg elundril |
hmm, daran hab ich nicht gedacht und es scheint zu klappen! :)
hier nochmal mein testcode, wie ich es jetzt gemacht habe:
Hauptunit:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TForm1 = class(TForm) ListBox1: TListBox; Button1: TButton; ListBox2: TListBox; Button2: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure ListBox1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private public end;
var Form1: TForm1;
implementation
uses Unit2;
var ThreadArray: array of TTestThread; ThreadRunning: array of Boolean;
{$R *.dfm}
procedure StartThread(ThreadName: string; ThreadIndex: integer); begin ThreadArray[ThreadIndex]:=TTestThread.Create(True); ThreadArray[ThreadIndex].FreeOnTerminate:=True; ThreadArray[ThreadIndex].ThreadName:=ThreadName; ThreadArray[ThreadIndex].Resume; ThreadRunning[ThreadIndex]:=True; end;
procedure StopThread(ThreadIndex: integer); begin ThreadArray[ThreadIndex].Terminate; ThreadRunning[ThreadIndex]:=False; end;
procedure TForm1.FormCreate(Sender: TObject); var i: integer; begin ListBox1.Clear; for i:=0 to 3 do begin ListBox1.Items.Append('Thread'+IntToStr(i+1)); end;
if Form1.ListBox1.Items.Count <> Form1.ListBox2.Items.Count then begin Form1.ListBox2.Clear; for i:=0 to Form1.ListBox1.Items.Count-1 do begin Form1.ListBox2.Items.Append('stopped'); end; end;
SetLength(ThreadArray, ListBox1.Items.Count); SetLength(ThreadRunning, ListBox1.Items.Count); for i:=low(ThreadRunning) to high(ThreadRunning) do begin ThreadRunning[i]:=False; end; end;
procedure TForm1.Button1Click(Sender: TObject); var aName: string; begin if ListBox1.ItemIndex > -1 then begin aName:=ListBox1.Items[ListBox1.ItemIndex];
if ThreadRunning[ListBox1.ItemIndex] then begin StopThread(ListBox1.ItemIndex); Form1.Button1.Caption:='Start'; end else begin StartThread(aName, ListBox1.ItemIndex); Form1.Button1.Caption:='Stop'; end; end; end;
procedure TForm1.ListBox1Click(Sender: TObject); var ThreadName: string; begin ThreadName:=ListBox1.Items[ListBox1.ItemIndex];
if ListBox1.ItemIndex > -1 then begin if ThreadRunning[ListBox1.ItemIndex] then begin Button1.Caption:='Stop'; end else begin ListBox2.Items[ListBox1.ItemIndex]:='stopped'; Button1.Caption:='Start'; end; end; end;
procedure TForm1.Button2Click(Sender: TObject); begin close; end;
end. |
Threadunit:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103:
| unit Unit2;
interface
uses Classes, Windows, SysUtils;
type TTestThread = class(TThread) ThreadName: string; private count: integer; public protected procedure Execute; override; procedure Sync; end;
implementation
uses Unit1;
function SecToDMS(Sekunden: int64): string; var RestSekunden, AllesInMinuten, RestMinuten, AllesInStunden,RestStunden, Tage, RestTage, Wochen: Int64; begin Result:='00:00:00';
try AllesInMinuten := Sekunden div 60; RestSekunden := Sekunden - (AllesInMinuten * 60); AllesInStunden := AllesInMinuten div 60; RestMinuten := AllesInMinuten - (AllesInStunden * 60); Tage:= AllesInStunden div 24; RestStunden:= AllesInStunden - (Tage * 24); Wochen := Tage div 7; RestTage := Tage - Wochen * 7;
if Sekunden >= 604800 then begin result := formatfloat('00',Wochen)+'W, '+ formatfloat('00',RestTage)+'T, '+ formatfloat('00',RestStunden)+':'+ formatfloat('00',RestMinuten)+':'+ formatfloat('00',RestSekunden); end;
if Sekunden < 604800 then begin result := formatfloat('00',RestTage)+'T, '+ formatfloat('00',RestStunden)+':'+ formatfloat('00',RestMinuten)+':'+ formatfloat('00',RestSekunden); end;
if Sekunden < 86400 then begin result := formatfloat('00',RestStunden)+':'+ formatfloat('00',RestMinuten)+':'+ formatfloat('00',RestSekunden); end;
except result := '00:00:00'; end; end;
procedure TTestThread.Sync; var i:integer; begin for i:=0 to Form1.ListBox1.Items.Count-1 do begin if Form1.ListBox1.Items[i] = ThreadName then begin if (not Terminated) then Form1.ListBox2.Items[i] := SecToDMS(count) else Form1.ListBox2.Items[i] := 'stopped'; end; end; end;
procedure TTestThread.Execute; begin count:=0; while not Terminated do begin inc(count); Synchronize(Sync); sleep(1000); end; Synchronize(Sync); end;
end. |
also bei jedem thread den ich erstelle zählt er mir jetzt den count so wie ich es haben wollte :)
falls jemand meint es gäbe eine andere/elegantere lösung, ich bin ganz ohr :D
auf jeden fall mal ein fettes
Dankeschön an
elundril [
http://www.delphi-forum.de/user_elundril.html] für die idee mit dem array :)
// Edit //
Leider hat das ganze mit "IsRunning" aus dem Thread nicht so funktioniert wie ich es haben wollte.
Deswegen ein Update -> noch ein Array of Boolean hinzugefügt, da mir jetzt nichts anderes eingefallen ist.
Gibt es eine andere möglichkeit zu prüfen ob ThreadX, welcher zu aName passt noch läuft?
Gerd Kayser - Fr 30.07.10 03:31
Folgendes Beispiel listet alle Threads (ohne den MainThread) auf, die vom eigenen Programm gestartet wurden und noch am laufen sind:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| procedure TForm1.Button2Click(Sender: TObject); var PE_Exe : TThreadEntry32; HProcList : THandle; HExe : THandle; HThread : THandle; begin Memo1.Clear; HExe := GetCurrentProcessID; HThread := GetCurrentThreadID; PE_Exe.dwSize := SizeOf(TThreadEntry32);
HProcList := CreateToolHelp32SnapShot(TH32CS_SnapThread, 0);
Thread32First(HProcList, PE_Exe); repeat if ((HExe = PE_Exe.th32OwnerProcessID) and (HThread <> PE_Exe.th32ThreadID)) then Memo1.Lines.Add(IntToStr(PE_Exe.th32ThreadID)); until not Thread32Next(HProcList, PE_Exe);
CloseHandle(HProcList); end; |
Beenden kann man die Threads mit TerminateThread.
fuba - Fr 30.07.10 04:48
Moderiert von
Narses: Komplett-Zitat des letzten Beitrags entfernt.
Schon klar, aber woher weiß ich welcher Thread (da ich ja nur die ThreadID bekomme) zu welchem Index in der ListBox gehört?
Mit der ThreadID kann ich zwar den jeweiligen Thread terminieren, aber nicht prüfen ob es eigentlich der richtige war (ThreadName prüfen).
Ich stelle mir das so vor (grob):
Klick auf Listbox-Eintrag-Thread1 -> Klick auf Start -> Thread1 Läuft
Klick auf Listbox-Eintrag-Thread2 -> Klick auf Start -> Thread2 Läuft
usw...
Das gleiche beim beenden:
Klick auf Listbox-Eintrag-Thread1 -> Klick auf Stop -> Thread1 wird beendet
Klick auf Listbox-Eintrag-Thread2 -> Klick auf Stop -> Thread2 wird beendet
usw...
Delete - Fr 30.07.10 06:21
Gerd Kayser hat folgendes geschrieben : |
| Beenden kann man die Threads mit TerminateThread. |
Was man aber tunlichst nicht machen sollte. Oder hältst du dein Auto an, in dem du es immer vor die Wand setzt?
Lege die ThreadIDs doch als Objekte mit in der Listbox ab. Oder besser, verwalte die Threads in einer ObjectList.
Gerd Kayser - Fr 30.07.10 07:45
Luckie hat folgendes geschrieben : |
| Was man aber tunlichst nicht machen sollte. |
Das ist so aber nicht richtig. Man kann Threads verwenden, um a) etwas abzuarbeiten, ohne den Hauptthread lahm zu legen, oder b) um zu
warten, ohne den Hauptthread zu blockieren.
Beispiel für einen Warte-Thread:
Man möchte feststellen, ob gewisse Laufwerkspfade im Netzwerk bereit sind. Bei mehreren Abfragen können sich die Zeiten bei nicht bereiten Laufwerken zu einer kleinen Ewigkeit summieren. (Die Warterei kann man gut im Windowsxplorer nachvollziehen, wenn man auf ein nicht bereites Laufwerk klickt.) Wenn man die Abfragen in Threads verlagert, kann man diese ggf. z. B. nach einer Sekunde abbrechen (also den Timeout drastisch verkürzen).
Beispiel:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| var Form1: TForm1; LWZustand : string; Thread_laeuft: boolean; [ ... ]
procedure TForm1.Button1Click(Sender: TObject); var LWInfo : ThInfo; begin LWZustand := 'Timeout'; Thread_laeuft := True;
LWInfo := ThInfo.Create('\\192.168.1.200\share\'); LWInfo.Priority := tpNormal; Sleep(1000); if Thread_laeuft then LWInfo.Terminate; Label1.Caption := LWZustand; end; |
Und hier der Thread dazu:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45:
| unit Th_Info;
interface
uses Windows, Classes;
type ThInfo = class(TThread) private protected LW: string; procedure Execute; override; public constructor Create(Laufwerk: String); end;
implementation
uses Unit1;
constructor ThInfo.Create(Laufwerk: String); begin inherited Create(false); FreeOnTerminate := true; LW := Laufwerk; end;
procedure ThInfo.Execute; var Buffer : array [0..11] of Char; Serien_Nr : cardinal; Dummy : cardinal; Flags : cardinal; begin if GetVolumeInformation(PChar(LW), Buffer, SizeOf(Buffer), @Serien_Nr, Dummy, Flags, nil, 0) then Unit1.LWZustand := 'Ready' else Unit1.LWZustand := 'Not Ready'; Unit1.Thread_laeuft := false; end;
end. |
Delete - Fr 30.07.10 14:05
Bitte richtig lesen. Ich bezog mich auf das Beenden eines Threads mittels TerminateThread. Denn da werden eventuell Ressourcen nicht mehr freigegeben und wenn sich der Thread gerade in einer CriticalSection befindet wird diese auch nicht mehr freigegeben und du hast ein Deadlock.
Und über die Verwendung von Threads brauchst du mich nicht aufklären:
http://www.michael-puff.de/Programmierung/Delphi/Tutorials/Threads/
fuba - Fr 30.07.10 15:29
Luckie hat folgendes geschrieben : |
Bitte richtig lesen. Ich bezog mich auf das Beenden eines Threads mittels TerminateThread. Denn da werden eventuell Ressourcen nicht mehr freigegeben und wenn sich der Thread gerade in einer CriticalSection befindet wird diese auch nicht mehr freigegeben und du hast ein Deadlock.
Und über die Verwendung von Threads brauchst du mich nicht aufklären: http://www.michael-puff.de/Programmierung/Delphi/Tutorials/Threads/ |
hab ich mir fast gedacht, wenn ich die threads per ThreadTerminate beende, irgendwas zurückbleibt, also unsauber ist.
aber noch ne frage:
wie mach ich das mit ner ObjectList und was währe anders zum vergleich mit dem array?
kann ich per ObjectList prüfen ob der ThreadX noch läuft?
(habe nämlich noch nie mit ObjectList gearbeitet)
Ein zusätzliches array dass mit sagt ob läuft oder nicht, ist auch nicht das ideale, finde ich.
(falls ein thread durch ne exception beendet wird, steht im array "ThreadRunning" noch immer "True".)
bummi - Fr 30.07.10 16:21
kleines Beispiel:
ist eigenlich egal ob List, Array o.ä.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91:
| unit Unit5;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TMyThread=Class(TThread) private FSleepTime:Integer; protected procedure Execute; override; public constructor CreateWithInfo(CreateSuspended:Boolean;SleepTime:Integer); end;
TForm5 = class(TForm) ListBox1: TListBox; Button1: TButton; procedure Button1Click(Sender: TObject); private procedure MyTerminate(Sender: TObject); procedure RunOneThread(Dauer: Integer); public end;
var Form5: TForm5;
implementation
{$R *.dfm}
constructor TMyThread.CreateWithInfo(CreateSuspended: Boolean;SleepTime:Integer); begin
inherited Create(CreateSuspended); FSleepTime := SleepTime; FreeOnTerminate := True;
end;
procedure TMyThread.Execute; begin inherited; Sleep(FSleepTime); end;
procedure TForm5.MyTerminate(Sender:TObject); var i:Integer; begin for I := 0 to Listbox1.Items.Count - 1 do begin if Listbox1.Items.Objects[i]=Sender then begin Listbox1.Items[i]:= Listbox1.Items[i] + ' bendet.'; Listbox1.Items.Objects[i]:= nil; end; end; end;
Procedure TForm5.RunOneThread(Dauer:Integer); begin Listbox1.Items.AddObject('1. Thread ' + IntToStr(DAuer) + ' Millisekunden', TMyThread.CreateWithInfo(true,dauer)); with TMyThread(Listbox1.Items.Objects[Listbox1.Items.Count - 1]) do begin ONTerminate := MyTerminate; Suspended := false; end;
end;
procedure TForm5.Button1Click(Sender: TObject); begin Randomize; RunOneThread(Random(5000) + 1000); end;
end. |
Gerd Kayser - Fr 30.07.10 17:45
fuba hat folgendes geschrieben : |
| hab ich mir fast gedacht, wenn ich die threads per ThreadTerminate beende, irgendwas zurückbleibt, also unsauber ist. |
Ich schrieb ja auch "kann" und nicht "muß" ... Wäre ich heute morgen nicht aus dem Bett geklingelt worden und ausgeschlafen gewesen, hätte ich das sicherlich anders formuliert. :)
| Zitat: |
| (falls ein thread durch ne exception beendet wird, steht im array "ThreadRunning" noch immer "True".) |
Man kann im Thread auch auf Exceptions reagieren, z. B. so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43:
| protected procedure Execute; override; procedure DoTerminate; override; procedure Sync; procedure SyncAbbruch; [ ... ] procedure TTestThread.Execute; begin count:=0; while not Terminated do begin inc(count); if count = 15 then raise EMathError.Create(''); Synchronize(Sync); sleep(1000); end; Synchronize(Sync); end; [ ... ] procedure TTestThread.DoTerminate; begin if FatalException is Exception then Synchronize(SyncAbbruch); inherited; end;
procedure TTestThread.SyncAbbruch; var i:integer; begin for i:=0 to Form1.ListBox1.Items.Count-1 do begin if Form1.ListBox1.Items[i] = ThreadName then Form1.ListBox2.Items[i] := 'Exception aufgetreten!'; end; end; |
Jetzt mußt Du nur noch was einbauen, das Dein ThreadArray aktualisiert. Für mich steht jetzt erst einmal ein sehr ausgiebiger Gassirundgang mit meiner Schäferhündin an.
fuba - Fr 30.07.10 23:42
Gerd Kayser hat folgendes geschrieben : |
Ich schrieb ja auch "kann" und nicht "muß" ... Wäre ich heute morgen nicht aus dem Bett geklingelt worden und ausgeschlafen gewesen, hätte ich das sicherlich anders formuliert. :)
|
ach was, bin froh über jede idee, also np :D
// Edit //
Code aus deiesem Bereich gelöscht, da er nicht korrekt funktioniert hat.
jaenicke - Sa 31.07.10 10:10
Nach Terminate kannst du übrigens mit WaitFor warten, dass er wirklich terminiert ist.
Gerd Kayser - Sa 31.07.10 14:38
fuba hat folgendes geschrieben : |
| sollte theoretisch klappen, auch wenn der Thread durch ne exception gekillt wird, oder? |
Mir sind folgende Punkte aufgefallen:
1. Deine Anwendung teilt dem Anwender nicht mit, daß eine (und welche) Exception aufgetreten ist. Wenn Du das Programm mal von außerhalb der IDE startest, siehst Du, daß die Exception nicht angezeigt wird.
2. SyncTerminate führt die letzte Aktion vor dem Beenden des Threads aus. Danach folgt inherited bei DoTerminate, und der Thread verabschiedet sich. Das ist eine Sache von wenigen Millisekunden. Also macht es wenig Sinn, in SyncTerminate den Thread nochmals zu stoppen. Das ist doppelt gemoppelt.
3. "ThreadArray[ThreadIndex]:=nil;" verhindert ein nochmaliges Anstarten. Ist das so gewollt?
4. Die Button-Captions und die ListBox-Einträge werden nicht aktualisiert.
fuba - Sa 31.07.10 17:46
Moderiert von
Narses: Komplett-Zitat des letzten Beitrags entfernt.
ja, ich weiß, mir ging es derzeit auch nur darum, mehrere Threads zu erstellen, zu prüfen ob ThreadX noch läuft und diesen beenden zu können.
1. Exception message wird noch eingebaut, wenn alles andere klappt wie ich es haben will
2. Das ist so gewollt, da ich es nun doch wieder mit ner array of byte mache, wo drin steht ob TreadX noch läuft.
3. hat sich erübrigt, da ich jetzt wieder mit array of byte prüfe
4. werde ich noch einbauen, danke für den fingerzeig, hätt ich fast vergessen :D
mache es jetzt übrigens so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56:
| ... procedure StartThread(ThreadName: string; ThreadIndex: integer); begin if (Not ThreadActive[ThreadIndex]) then begin ThreadArray[ThreadIndex]:=TTestThread.Create(True); ThreadArray[ThreadIndex].FreeOnTerminate:=True; ThreadArray[ThreadIndex].ThreadName:=ThreadName; ThreadArray[ThreadIndex].Resume; ThreadActive[ThreadIndex] := True; end; end;
procedure TForm1.StopThread(ThreadName: string; ThreadIndex: integer); begin if ThreadActive[ThreadIndex] then begin if (ThreadArray[ThreadIndex].ThreadName = ThreadName) then begin try ThreadArray[ThreadIndex].Terminate; finally ThreadActive[ThreadIndex] := False; end; end; end; end;
function IsThreadActive(Index: integer): Bool; begin if ThreadArray[Index] <> nil then begin Result:=ThreadActive[Index]; end else Result:=False; end;
procedure TForm1.FormCreate(Sender: TObject); var i: integer; begin if Form1.ListBox1.Items.Count <> Form1.ListBox2.Items.Count then begin for i:=0 to Form1.ListBox1.Items.Count-1 do begin Form1.ListBox2.Items.Append('00:00:00'); end; end;
SetLength(ThreadArray, ListBox1.Items.Count); SetLength(ThreadActive, ListBox1.Items.Count); for i:=low(ThreadActive) to high(ThreadActive) do begin ThreadActive[i] := False; end; Disable; end; |
ThreadUnit änderung:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54:
| procedure TTestThread.SyncTerminate; var i:integer; begin for i:=0 to Form1.ListBox1.Items.Count-1 do begin if Form1.ListBox1.Items[i] = ThreadName then begin Form1.ListBox2.Items[i]:='00:00:00'; Form1.ListBox3.Items[i]:='00:00:00'; Form1.StartStopButton.Caption:='Start'; Form1.StopThread(ThreadName, i); end; end; end;
procedure TTestThread.Sync; var i:integer; begin for i:=0 to Form1.ListBox1.Items.Count-1 do begin if Form1.ListBox1.Items[i] = ThreadName then begin if (not Terminated) then begin Form1.ListBox2.Items[i] := SecToDMS(count); end else begin Form1.ListBox2.Items[i]:='00:00:00'; Form1.StartStopButton.Caption:='Start'; end; end; end; end;
procedure TTestThread.Execute; begin count:=0; while (not Terminated) do try inc(count); Synchronize(Sync); sleep(1000); finally end; Synchronize(Sync); end;
procedure TTestThread.DoTerminate; begin if FatalException is Exception then Synchronize(SyncTerminate); inherited; end; |
jetzt aber noch ne frage zu ObjectList:
könnte ich mit ner Objectlist auf anderem weg, außer nem array of bool, prüfen ob ThreadX noch läuft?
wenn ja, werde ich mir das nochmal genauer ansehen.
Danke an alle die mir bisher geholfen haben!
lg. fuba
// Edit //
die Exception kann ich ja im SyncTerminate in eine TextFile speichern oder?
habe mir das so vorgestellt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TTestThread.SyncTerminate; var i:integer; EL: TSTringList; begin for i:=0 to Form1.ListBox1.Items.Count-1 do begin if Form1.ListBox1.Items[i] = ThreadName then begin Form1.ListBox2.Items[i]:='00:00:00'; Form1.StartStopButton.Caption:='Start'; Form1.StopThread(ThreadName, i); end; end;
EL := TStringList.Create; EL.Append(Exception(FatalException).Message); EL.SaveToFile(ExtractFilePath(ParamStr(0)) + 'LastError_'+ThreadName+'.txt'); EL.Free; end; |
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!