Probleme beim Warten auf 2 Threads
Hallo,
ich probiere schon seit langem rum, wie ich auf 2 Threads warten kann. Ich habe jetzt folgende Ausgangssituation :
Delphi-Quellcode:
So erstelle ich meine Classen für die Threads.
TSearchCopy = class(TThread)
private { Private-Deklarationen } public procedure Execute; override; end; TSearchDelete = class(TThread) private { Private-Deklarationen } public procedure Execute; override; end;
Delphi-Quellcode:
Und so starte ich es. In der Execute-Procedure wird nach Dateien gesucht. Dieses wird auch sauber angezeigt und funktioniert auch soweit sehr gut. Ich habe schon versucht, auf die beiden Threads mit :
procedure TMainForm.BtnCopyClick(Sender: TObject);
begin . . . // Fenster anzeigen, wo er gerade sucht ProgressWindow.Visible := not ProgressWindow.Visible; SearchForCopy := TSearchCopy.Create(false); SearchForDelete := TSearchDelete.Create(false); // hier soll gewartet werden, bis die beiden Threads fertig sind // denn hier folgt weitere Sourcecode, der nach dem ausführen der Threads ausgeführt werden soll . . . end;
Delphi-Quellcode:
zu warten, was aber leider nicht zum Erfolg führt. Wie kann ich das anderst machen ? Muss ich eventuell den Aufruf ändern oder das warten auf die Threads ?
repeat
Application.ProcessMessages; until (SearchForCopy.Terminate) and (SearchForDelete.Terminate); |
Re: Probleme beim Warten auf 2 Threads
Mit TThread.WaitFor kannst du auf einen Thread warten. Dieser Aufruf wartet solange, bis die Execute-Funktion des Threads beendet wird.
Wenn du währenddessen noch Dinge erledigen willst, dann sollten die Threads einfach z.B. einen Status setzen, den du abfragst. karlkoch |
Re: Probleme beim Warten auf 2 Threads
Wenn ich jetzt
Delphi-Quellcode:
Dort einsetze kommt nach kurzer Zeit die Fehlermeldung
SearchForCopy.WaitFor;
SearchForDelete.WaitFor; Zitat:
Habe ich eventuell etwas falsch gemacht ? |
Re: Probleme beim Warten auf 2 Threads
Vermutlich wartet er im ersten Thread mit dem WaitFor bis dieser beendet ist. Und wenn dies eingetreten ist ruft er WaitFor vom zweiten Thread auf - der hatte aber die Wartezeit auf den ersten Thread genutzt und ist schon beendet.
Meine Vermutung... |
Re: Probleme beim Warten auf 2 Threads
Ich habe das ganze jetzt mal im Einzelschritt ausgeführt. Wenn ich dann die Zeile
Delphi-Quellcode:
ausführe, passiert auf dem Bildschirm für kurze Zeit garnichts und dann kommt der Fehler aus meinem letzten Beitrag. Gibt es noch andere Möglichkeiten auf Threads zu warten ?
SearchForCopy.WaitFor;
|
Re: Probleme beim Warten auf 2 Threads
Hi,
setzt mal die property FreeOnTerminate deiner beiden Threads auf false. Du musst dann natürlich nach den beiden WaitFor's die Threads selber freigeben Dann sollte es gehen. Gruss |
Re: Probleme beim Warten auf 2 Threads
Erstmal ein dickes Danke an Thomas. Ich habe das ganze jetzt so gelöst :
Delphi-Quellcode:
Kann mir jetzt noch jemand erklären, warum ich die TThreads selber freigeben muss und nicht über FreeOnTerminate ?
try
SearchForCopy := TSearchCopy.Create(false); SearchForCopy.FreeOnTerminate := False; SearchForCopy.WaitFor; SearchForDelete := TSearchDelete.Create(false); SearchForDelete.FreeOnTerminate := False; SearchForDelete.WaitFor; finally SearchForCopy.Free; SearchForDelete.Free; end; Jetzt habe ich nur noch das Problem, das mein Statusfenster zwar geöffnet wird aber nichts anzeigt von dem was meine beiden Threads macht. Wie löse ich das jetzt noch ? |
Re: Probleme beim Warten auf 2 Threads
Zitat:
So hatte ich das nicht gemeint - hier laufen jetzt die zwei hintereinander ab. Besser wäre
Delphi-Quellcode:
So können die beiden Threads parallel laufen.
try
SearchForCopy := TSearchCopy.Create(true); // create suspended ! SearchForCopy.FreeOnTerminate := False; SearchForDelete := TSearchDelete.Create(true); // create suspended ! SearchForDelete.FreeOnTerminate := False; SearchForCopy.Resume; // thread laufen lassen SearchForDelete.Resume; // thread laufen lassen SearchForCopy.WaitFor; // warte auf Ende SearchForDelete.WaitFor; // warte auf Ende finally SearchForCopy.Free; SearchForDelete.Free; end; Das mit dem Freigeben hat folgenden Sinn: Damit das WaitFor überhaupt funktioniert - darf sich der Thread am Ende nicht selber freigeben, sonst bekommst Du eine Zugriffsverletzung. Also musst Du das selber erledigen. Gruss |
Re: Probleme beim Warten auf 2 Threads
Danke Dir Thomas für die Erklärung. Ich habe aber jetzt immer noch das Problem, dass in meinem Fenster nichts angezeigt wird durch das WaitFor. Wie kann ich das jetzt noch bereinigen ?
|
Re: Probleme beim Warten auf 2 Threads
Ach ja.....
Dann war dein erster Ansatz doch nicht so schlecht....
Delphi-Quellcode:
Dies anstelle der WaitFor eingesetzt sollte helfen.
repeat
Application.ProcessMessages; sleep(1); // lass den Threads auch eine Chance zu arbeiten. until (SearchForCopy.Terminated) and (SearchForDelete.Terminated); // achtung !! Terminated abfragen, nicht Terminate aufrufen. Allerdings auch hier wichtig - FreeOnTerminate auf false lassen und am Ende selber freigeben. Gruss |
Re: Probleme beim Warten auf 2 Threads
Hallo Rolf.
Das WaitFor im Hauptthread der Anwendung einzubaue ist nicht sinnvoll. Damit konstruiert du genau das, was du zu vermeiden versuchst - das "Hängenbleiben" deiner Anwendung. Es bleibt also nichts anderes, als die Threads für sich separat arbeiten zu lassen und über eine Ereignisbehandung bzw. Signale zu kommunizieren, um damit eben nicht aktiv zu warten. Ich möchte daher noch eine andere Läsung vorschlagen: Hast du dir die Delphi-Hilfe dazu einmal angesehen?
Zitat:
Panthrax. |
Re: Probleme beim Warten auf 2 Threads
Irgendwie klappt das nicht. Denn einer beiden Threads gibt kein True zurück, deshalb bleibt es in der repeat-Schleife hängen.
Zitat:
|
Re: Probleme beim Warten auf 2 Threads
Hi,
Du köntest auch per msgWaitForMultipleObjekts oder WaitForMultipleObjekts auf die Threads warten. z.B. so:
Delphi-Quellcode:
Var dwWaitResult : DWORD; ThreadArray : array[0..1] of THandle; // Handle Array um auf Threads zu warten begin SearchForCopy := TSearchCopy.Create(false); SearchForCopy.FreeOnTerminate := False; SearchForDelete := TSearchDelete.Create(false); SearchForDelete.FreeOnTerminate := False; ThreadArray[0] := SearchForCopy.Handle; // Handle Array füllen ThreadArray[1] := SearchForDelete; repeat // Auf Threads warten dwWaitResult := msgWaitforMultipleObjects(length(ThreadArray), ThreadArray, true, 100, QS_ALLINPUT); if dwWaitResult <> WAIT_OBJECT_0 then begin Application.ProcessMessages; // GUI aktualisieren end; until dwWaitResult = WAIT_OBJECT_0; // keinen Threads mehr zum warten end; |
Re: Probleme beim Warten auf 2 Threads
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Rolf.
Ich beschreibe dir hier das Konzept noch einmal etwas genauer. Im Anhang habe ich das Konzept in einem Beispielprojekt gezeigt. Das Konzept für 2 Threads Du willst auf die Beendigung zweier Threads warten. Dafür bietet sich das OnTerminate-Ereignis der Klasse TThread an. Die Ereignisbehandlungsroutine braucht die Informationen über
Ein Beispiel Im Beispiel habe ich die Klasse TSleepThread von TThread abgeleitet. Die Aufgabe ist eine bestimmte Zeit zu schlafen. Anschließend ist der Thread beendet. Wie lange geschlafen werden soll wird im Kontruktor angegeben. Ther Parameter CreateSuspended wird an den Kontruktor von TThread weitergereicht. Kurzfassung:
Delphi-Quellcode:
Zum Formular habe ich 2 Variablen (Eigenschaften) hinzugefügt: FThread1 (Thread1) und FThread2 (Thread2). Beide sind von der Klasse TSleepThread. Diese Felder dienen nur zum Merken, ob ein Thread beendet ist (= nil) oder nicht (<> nil). Kurzfassung:
type
TSleepThread = class(TThread) ... constructor TSleepThread.Create(const Milliseconds: Cardinal; const CreateSuspended: Boolean);
Delphi-Quellcode:
Die Methode RunThreads initialisiert und startet die Threads. Kurfassung:
type
TForm1 = class(TForm) private FThread1, FThread2: TSleepThread; published property Thread1: TSleepThread read FSleepThread1 write FSleepThread1; property Thread2: TSleepThread read FSleepThread2 write FSleepThread2; end;
Delphi-Quellcode:
Der Kern liegt in der Methode DoTerminate. Diese wurde den erzeugten Threads dem Ereignis OnTerminate zugewiesen. Neben einer Ausgaberückmeldung setzt diese Methode die Merker Thread1 bzw. Thread2 auf Nil, wenn der zugehörige Thread beendet wurde. Wurden beide abgearbeitet, sind folglich beide Nil. Das ist also der Zustand, nach dem du gesucht hast. Kurzfassung:
procedure RunThreads;
Delphi-Quellcode:
Damit ergibt sich also nicht mehr das Problem, dass das Programm "hängt".
procedure TForm1.DoTerminate(Sender: TObject);
begin { Merker setzten, dass ein Thread beendet wurde. } if Sender = Thread1 then Thread1:=nil else if Sender = Thread2 then Thread2:=nil; { Fall, dass beide Threads beendet wurden. } if not Assigned(Thread1) and not Assigned(Thread2) then...; end; Viel Spaß beim ausprobieren mit dem Beispiel. Ich habe es so gestaltet, dass man die "Laufzeit" der Threads einfach in der Oberfläche einstellen kann. Beispiel erstellt und getestet mit Delphi 7 Enterprise. Gruß, Panthrax. [edit=Panthrax]Glatt den Anhang vergessen... Jetzt ist er dabei.[/edit] |
Re: Probleme beim Warten auf 2 Threads
Ersteinmal ein dickes Danke an Christian, den sein Code funktioniert schon mal, wenn auch nicht ganz mit der Performance, als wenn ich nach dem Aufruf einfach die OnClick-Procedure beende.
Auch ein nochmaliges Danke an Dich Panthrax für Deine ausführliche Beschreibung. Verstehe ich das soweit richtig, dass der Code der nach der Ausführung der beiden Threads ausgeführt werden soll in der DoTerminate-Procedure stehen muss ? Wenn ja, wäre das nicht ganz Sinnvoll, da der Start von den beiden Threads in einer For-Schleife steht. |
Re: Probleme beim Warten auf 2 Threads
Schön, dass es dir gefällt.
Ob der Code, der nach Abschluss beider Threads ausgeführt werden soll, in der Ereignisbehandlungsroutine von OnTerminate stehen sollte oder nicht, kann ich nicht beurteilen. Fest steht, dass dort auf diesen Zustand reagiert werden kann. Sei es durch direktes Fortführen des Programmablaufs dort oder durch Anstoßen eines anderen Programmteils. Ich würde sehr wahrscheinlich eine Routine schreiben, die diese sich anschließenden Aufgaben übernimmt. Um dir jedoch dabei helfen zu können, bäuchte man schon etwas genauere Angaben, als "steht in einer For-Schleife". Es bleibt die Frage: Was hat die For-Schleife damit zu tun? Gruß, Panthrax. |
Re: Probleme beim Warten auf 2 Threads
Also, ich habe das ganze mal gestern Abend nach dem Beispiel von Panthrax in mein Programm versucht umzusetzen. Es hat leider nicht funktioniert. Ich muss doch meine ganze Struktur im Programm ändern.
Zitat:
|
Re: Probleme beim Warten auf 2 Threads
Hi,
Warum langsam? bei mir funktionirt der recht schnell und gut. Die Threads sind ja von dieser Funktion unabhängig. Solltest du allerdings aus dem Thread direkt auf ein Element der GUI zugreifen (Auch über Syncronize) dann dauert es natürlich bis zu 100 ms bis dein Code fortgesetzt wird. Ich vermute du verwendest diesen Code in CopyandSync und aktualisierst bei jedem Durchlauf von FindFirst / FindNext den Text deiner Statusbar so wird höchstens alle 100ms eine Datei gefunden! Das Stichwort heist hier Messages oder du setzt eine Variable im Thread/Hauptprogramm den du vor Application.ProcessMessages ausließt und in Statusbar schreibst. |
Re: Probleme beim Warten auf 2 Threads
Zitat:
Zitat:
Zitat:
|
Re: Probleme beim Warten auf 2 Threads
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
// Im Hauptprog
SearchForCopy := TSearchCopy.Create(false); SearchForCopy.FreeOnTerminate := False; SearchForCopy.Message := @MessageString;
Delphi-Quellcode:
Und setze dann diese Meldung alle 100ms in meine Anzeige:
//im Thread
Message^ := 'Kopiere Datei xyz'; if dwWaitResult <> WAIT_OBJECT_0 then begin Label1.Caption := MessageString; Application.ProcessMessages; // GUI aktualisieren end; Frei getippt! p.s.: Es scheint ein Problem mit meinem Code (vor allem mit dem fWaitAll) zu geben schau mal hier:msgWait... sollte aber nicht weiter schlimm sein. Damit gehts.
Delphi-Quellcode:
dwWaitResult := WaitforMultipleObjects(length(ThreadArray), @ThreadArray, true, 100);
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:58 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz