AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

mehrere Threads sauber beenden

Ein Thema von haentschman · begonnen am 10. Jan 2011 · letzter Beitrag vom 9. Dez 2013
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.297 Beiträge
 
Delphi 12 Athens
 
#1

mehrere Threads sauber beenden

  Alt 10. Jan 2011, 08:07
Delphi-Version: XE
Guten Morgen alle...

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...
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 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:
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;
* 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.

Variante 2:
- FreeOnTerminate:= False;
Delphi-Quellcode:
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;
* 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.

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:
Thread.Create;
///
Thread.WaitFor;
ThreadFree;
* das funktioniert auch, nur laufen die Threads nicht parallel sondern nacheinander. (logisch)

Bitte bringt etwas Licht ins Dunkel... Danke
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.755 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 09:09
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
Klaus
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.297 Beiträge
 
Delphi 12 Athens
 
#3

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 09:28
Zitat:
Form im onCloseQuery abfragst ob noch Threads laufen.
...das dumme ist nur, daß die Threads stehen bleiben wenn du dich im OnClose OnCloseQuery befindest. (warum auch immer das so ist... wenn das einer logisch erklären kann, bitte) Das war ja mein erster Ansatz... Warten bis die Liste leer ist. Im OnClose / OnCloseQuery kannst du warten bis du schwarz wirst

...aber Danke für deine Hilfe.

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 ?

Geändert von haentschman (10. Jan 2011 um 09:56 Uhr)
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.755 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 10:18
Hallo,

mal ein kleines Konstrukt:

Delphi-Quellcode:
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;
Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.297 Beiträge
 
Delphi 12 Athens
 
#5

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 10:24
Danke für deine Mühe...

Delphi-Quellcode:
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;
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.
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.541 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 10:32
Unter Delphi 2007 funktioniert das Beispiel einwandfrei.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.755 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 10:33
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
Klaus
  Mit Zitat antworten Zitat
Benutzerbild von haentschman
haentschman

Registriert seit: 24. Okt 2006
Ort: Seifhennersdorf / Sachsen
5.297 Beiträge
 
Delphi 12 Athens
 
#8

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 10:42
ok... diese Variante hatte ich wie gesgt schon. Allerdings nicht mit Sleep.

Ich geh dann mal zum probieren....bis gleich.

Soooo....
Delphi-Quellcode:
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;
also Terminated auskommentiert.
Delphi-Quellcode:
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;
bei beiden Varianten im Execute Sleep(100) eingefügt...

Ergebnis: Die Threads stehen wie eine eins und das Programm ist in einer Endlosschleife.

Geändert von haentschman (10. Jan 2011 um 11:05 Uhr)
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.755 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 11:12
.. kannst Du mal (so grob) Deine Thread.execute Methode
hier einstellen.

Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#10

AW: mehrere Threads sauber beenden

  Alt 10. Jan 2011, 11:19
Zitat:
Ergebnis: Die Threads stehen wie eine eins und das Programm ist in einer Endlosschleife.
Macht mit Sleep keinen Sinn.
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:
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;
gruss
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:19 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