![]() |
Delphi-Version: XE
mehrere Threads sauber beenden
Guten Morgen alle... :hi:
am Wochenende hab ich mich mal mit Threads intensiv beschäftigt. Zuerst hab ich die OmniThreadLibary ausprobiert. So viele MemoryLeaks (aus der Libary) hab ich in meinem Leben noch nicht gesehen. Danach hab ich TThread versucht. Nach gefühlten hunderten Forenbeiträgen, Hilfeseiten und ausprobieren dessen habe ich das Gefühl die Katze beißt sich in den Schwanz... :zwinker: Gegeben: - Mainunit - UnitA - enthällt KlasseA - UnitB - enthällt KlasseB(TThread) mit IdHTTP Funktion: - Mainunit instanziert Objekt von KlasseA - KlasseA erzeugt TObjectlist für die Threads - KlasseA erzeugt Objekte von KlasseB (je nach Anfrage 1-4) - beim Erzeugen des Threads wird der Thread in die Objectlist gelegt - im OnTerminate des Threads das Objekt aus der Liste entfernt - Threads sollen parallel laufen also nicht warten bis einer fertig ist Solange das Programm beendet wird wenn kein Thread am laufen ist, ist alles in Ordnung. Wird die Anwendung bei laufenden Threads beendet bleiben die Threads stehen :shock: Macht man weiter gibt es MemoryLeaks in den Indys weil die Threads einfach abgewürgt werden. Ok, dachte ich, manuell entfernen... Variante 1: - FreeOnTerminate:= True // Threads sollen sich selbst freigeben wenn beendet
Delphi-Quellcode:
* gibt Zugriffsverletungen... Inzwischen weiß ich, daß WaitFor in Verbindung mit FreeOnTerminate nicht zu gebrauchen ist, da das Handle irgendwo weggeworfen wird und dieser "Bug" schon ein paar Jahre existiert.
destructor KlasseA.Destroy;
begin while not (FThreadList.Count = 0) do begin if Assigned((FThreadList.Items[0] as KlasseB)) then (FThreadList.Items[0] as KlasseB).WaitFor; end; end; Variante 2: - FreeOnTerminate:= False;
Delphi-Quellcode:
* soweit so gut. Die aktuellen Threads laufen fertig und sind freigegeben. Nur hab ich dann Im laufenden Betrieb noch haufenweise Objekte im Speicher, welche nicht mehr in der ObjectList stehen, da die Threads sich im OnTerminate austragen.
destructor KlasseA.Destroy;
begin while not (FThreadList.Count = 0) do begin if Assigned((FThreadList.Items[0] as KlasseB)) then begin (FThreadList.Items[0] as KlasseB).WaitFor; (FThreadList.Items[0] as KlasseB).Free; end; end; end; Wo gebe ich quasi im laufenden Betrieb die Objekte frei ? (nach OnTerminate). Die Beiträge in den Foren laufen alle im Prinzip auf folgendes hinaus:
Delphi-Quellcode:
* das funktioniert auch, nur laufen die Threads nicht parallel sondern nacheinander. (logisch)
Thread.Create;
/// Thread.WaitFor; ThreadFree; Bitte bringt etwas Licht ins Dunkel... Danke :hi: |
AW: mehrere Threads sauber beenden
Guten Morgen,
wenn Du die Threads weiter mit freeOnTerminate = true startest und in der Form im onCloseQuery abfragst ob noch Threads laufen. ObjectList.count > 0 und die noch laufenden Threads dann terminierst (oder wartest bis sie abgearbeitet sind) sollte es doch "eigentlich" zu keinen Problemen kommen. Grüße Klaus |
AW: mehrere Threads sauber beenden
Zitat:
...aber Danke für deine Hilfe. :P Nachtrag: Nur mit WaitFor bringt man den entsprechenden Thread zum weiterlaufen. Funktioniert aber nur bei FreeOnTerminate:= False. Und dann stehen wir wieder am Anfang...wo gebe ich die Threads frei ? :zwinker: |
AW: mehrere Threads sauber beenden
Hallo,
mal ein kleines Konstrukt:
Delphi-Quellcode:
Grüße
constructor TTestThread.create;
begin inherited create(false); freeOnTerminate := true; end; procedure TTestThread.execute; begin while not terminated do begin sleep(100); end; end; procedure TForm1.Button1Click(Sender: TObject); begin ThreadList.Add(TTestThread.Create) end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin showMessage(intToStr(threadList.count)); threadList.free; end; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); var i : Byte; begin canClose := false; while ThreadList.Count > 0 do begin for i:= ThreadList.count -1 downto 0 do begin (ThreadList[i] as TTestThread).terminate; while not (ThreadList[i] as TTestThread).Terminated do begin sleep(200); end; ThreadList.Delete(i); end; end; canClose := true; end; procedure TForm1.FormCreate(Sender: TObject); begin ThreadList := TObjectList.Create(false); end; Klaus |
AW: mehrere Threads sauber beenden
Danke für deine Mühe...
Delphi-Quellcode:
aus dieser Schleife kommst du nicht mehr raus, da die Threads einfach stehen. Da kannst du Terminate setzen wie du willst. Terminated wird nie True, weil die Threads nicht arbeiten. Sprich Threadlist.Count bleibt immer das gleiche. Würden die Threads ganz normal weiterlaufen würde dein Konstrukt funktionieren.
for i:= ThreadList.count -1 downto 0 do
begin (ThreadList[i] as TTestThread).terminate; while not (ThreadList[i] as TTestThread).Terminated do begin sleep(200); end; ThreadList.Delete(i); end; |
AW: mehrere Threads sauber beenden
Unter Delphi 2007 funktioniert das Beispiel einwandfrei.
|
AW: mehrere Threads sauber beenden
Hallo,
schon merkwürdig. Wenn ich im execute des Threads ein Sleep von 20 einsetze funktioniert es so wie Du beschrieben hast. Wenn ich aber ein Sleep von 100 einsetze terminiert der Thread und ich bekomme am Ende die Messagebox angezeigt. Grüße Klaus |
AW: mehrere Threads sauber beenden
ok... diese Variante hatte ich wie gesgt schon. Allerdings nicht mit Sleep.
Ich geh dann mal zum probieren....bis gleich. Soooo....
Delphi-Quellcode:
also Terminated auskommentiert.
destructor Klasse1.Destroy; // Kommt auf das gleiche raus wie CloseQuery
var I: Integer; begin while not (FThreadList.Count = 0) do begin if Assigned((FThreadList.Items[0] as TXWebLoader)) then begin while FThreadList.Count > 0 do begin for I := FThreadList.Count - 1 to 0 do begin (FThreadList.Items[0] as TXWebLoader).Terminate; // in XE ist Terminated als protected deklariert ! Geht schon mal nicht ! while not (FThreadList.Items[0] as TXWebLoader).Terminated do begin Sleep(200); end; end; end; FThreadList.Delete(I); end; end;
Delphi-Quellcode:
bei beiden Varianten im Execute Sleep(100) eingefügt...
destructor TXWeb.Destroy;
var I: Integer; begin while not (FThreadList.Count = 0) do begin if Assigned((FThreadList.Items[0] as TXWebLoader)) then begin while FThreadList.Count > 0 do begin for I := FThreadList.Count - 1 to 0 do begin (FThreadList.Items[0] as TXWebLoader).Terminate; Sleep(200); end; end; FThreadList.Delete(I); end; end; Ergebnis: Die Threads stehen wie eine eins und das Programm ist in einer Endlosschleife. |
AW: mehrere Threads sauber beenden
.. kannst Du mal (so grob) Deine Thread.execute Methode
hier einstellen. Grüße Klaus |
AW: mehrere Threads sauber beenden
Zitat:
Damit hälst du doch nur alle Threads an und das Programm steht für 200 Millisekunden Du solltest allen Threads die möglichkeit geben ihre Aktionen zu beenden. Versuchs mal damit
Delphi-Quellcode:
gruss
procedure WinProcessMessages;
// Allow Windows to process other system messages var ProcMsg: TMsg; begin while PeekMessage(ProcMsg, 0, 0, 0, PM_REMOVE) do begin if (ProcMsg.message = WM_QUIT) then Exit; TranslateMessage(ProcMsg); DispatchMessage(ProcMsg); end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:00 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz