| Autor |
Beitrag |
fuba
      
Beiträge: 125
Win7
D7 Ent.
|
Verfasst: Fr 30.07.10 00:20
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:
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
      
Beiträge: 3747
Erhaltene Danke: 123
Windows Vista, Ubuntu
Delphi 7 PE "Codename: Aurora", Eclipse Ganymede
|
Verfasst: 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
_________________ This Signature-Space is intentionally left blank.
Bei Beschwerden, bitte den Beschwerdebutton (gekennzeichnet mit PN) verwenden.
|
|
fuba 
      
Beiträge: 125
Win7
D7 Ent.
|
Verfasst: 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:
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:
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
auf jeden fall mal ein fettes Dankeschön an elundril 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?
Zuletzt bearbeitet von fuba am Fr 30.07.10 04:59, insgesamt 3-mal bearbeitet
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: 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 
      
Beiträge: 125
Win7
D7 Ent.
|
Verfasst: 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...
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: 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
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: 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: 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. |
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: 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: www.michael-puff.de/...i/Tutorials/Threads/
|
|
fuba 
      
Beiträge: 125
Win7
D7 Ent.
|
Verfasst: 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: www.michael-puff.de/...i/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
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: Fr 30.07.10 16:21
kleines Beispiel:
ist eigenlich egal ob List, Array o.ä.
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
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: 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:
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 
      
Beiträge: 125
Win7
D7 Ent.
|
Verfasst: 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
// Edit //
Code aus deiesem Bereich gelöscht, da er nicht korrekt funktioniert hat.
Zuletzt bearbeitet von fuba am Sa 31.07.10 17:47, insgesamt 1-mal bearbeitet
|
|
jaenicke
      
Beiträge: 19340
Erhaltene Danke: 1752
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 31.07.10 10:10
Nach Terminate kannst du übrigens mit WaitFor warten, dass er wirklich terminiert ist.
|
|
Gerd Kayser
      
Beiträge: 632
Erhaltene Danke: 121
Win 7 32-bit
Delphi 2006/XE
|
Verfasst: 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 
      
Beiträge: 125
Win7
D7 Ent.
|
Verfasst: 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
mache es jetzt übrigens so:
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:
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; |
|
|
|