![]() |
AW: Arbeiten mit TThreadList
Zitat:
Vielleicht kam das erst mit XE? Aber ansonsten wäre es kein Unterschied, stattdessen mit (weitaus mehr Tippaufwand) sich auf klassischem Wege wieder eine Klasse
Delphi-Quellcode:
zu definieren,
TMyThread = class(TThread)
Delphi-Quellcode:
zu implementieren und den letztendlich zurückzugeben.
Execute()
|
AW: Arbeiten mit TThreadList
Ich verstehe gar nicht, was dieses Gehampel mit den Threads soll.
Delphi-Quellcode:
(ja, OwnsObjects auf True) und wenn diese Threads aus dem Speicher sollen, dann ein ganz lapidares freigeben der Liste.
TObjectList
Ein Thread ruft im Destroy ganz von alleine das ![]()
Delphi-Quellcode:
.
TThread.WaitFor
Fazit: Die Thread-Klasse sauber aufbauen, dann klappt das wie von selber |
AW: Arbeiten mit TThreadList
Zitat:
|
AW: Arbeiten mit TThreadList
Apropos WaitFor. Darf ich mich mal kurz einklinken? Kann man das auch in den destructor schreiben oder ist es da schon zu spät?
Delphi-Quellcode:
constructor TFindSnapPointsThread.Create(List: TGraphicList);
begin inherited Create(true); FreeOnTerminate := true; FFindSnapPoints := TFindSnapPoints.Create; FList := List end; destructor TFindSnapPointsThread.Destroy; begin WaitFor; FFindSnapPoints.Free; inherited Destroy; end; procedure TFindSnapPointsThread.Terminate; begin FFindSnapPoints.Cancel := true; inherited Terminate; end; |
AW: Arbeiten mit TThreadList
Es sollte reichen, wenn du die Instanzen nach dem
Delphi-Quellcode:
freigibst.
inherited
Delphi-Quellcode:
Um hier aber etwas wirklich konkretes zu sagen, musst du dir dringend einmal anschauen, was in
destructor TFindSnapPointsThread.Destroy;
begin inherited; FFindSnapPoints.Free; end;
Delphi-Quellcode:
so passiert.
TThread.Destroy
In den neueren Delphi-Versionen wird dort eben genau das alles gemacht (
Delphi-Quellcode:
,
Terminate
Delphi-Quellcode:
,...).
WaitFor
Zitat:
Delphi-Quellcode:
zu klären sein, ob das wirklich nötig ist, oder ob es einfach reicht, den echten Destructor abzuwarten und dann erst alles einzureißen (s.o.)
TThread.Destroy
|
AW: Arbeiten mit TThreadList
Hier mal ein Beispiel-Thread, der sich nach außen hin "harmlos" verhält.
Delphi-Quellcode:
TMyForm = class( TForm )
procedure Button1Click( Sender:TObject ); private FMyThread : TMyThread; public procedure AfterConstruction; override; procedure BeforeDestruction; override; end; procedure TMyThread.Button1Click( Sender:TObject ); var LFoo : TFoo; begin // Feed the Thread ... LFoo := TFoo.Create; try FMyThread.WorkOnItem( LFoo ); LFoo := nil; // Wenn die Instanz vom Thread übernommen wurde, dann hier auf nil setzen finally LFoo.Free; // stellt bei einer Exception sicher, dass die Instanz freigegeben wird end; end; procedure TMyForm.AfterConstruction; begin inherited; FMyThread :=TMyThread.Create; end; procedure TMyForm.BeforeDestruction; begin FreeAndNil( FMyThread ); // erst wenn die Thread-Instanz wirklich freigegeben werden konnte, dann geht es hier weiter inherited; end;
Delphi-Quellcode:
UPDATE
unit Unit1;
interface // In älteren Delphi-Versionen hat die Thread-Klasse noch keine TerminatedSet-Methode. // Dann bitte das nachfolgende {$DEFINE USE_TERMINATEDSET} ausschalten {$DEFINE USE_TERMINATEDSET } uses Classes, SyncObjs, Contnrs; type TMyThread = class( TThread ) private FCS : TCriticalSection; FEvent : TEvent; FToDoList : TObjectList; procedure DoWorkOnItem( Item : TObject ); function GetItem : TObject; protected procedure Execute; override; {$IFDEF USE_TERMINATEDSET} procedure TerminatedSet; override; {$ENDIF} public constructor Create; destructor Destroy; override; // Übergabe eines WorkItems an den Thread. // Der Thread übernimmt die Kontrolle über die Item-Instanz // und gibt diese bei Bedarf auch wieder frei // - Nach dem Abarbeiten // - Beim Beenden, wenn noch Items in der Liste enthalten sind procedure WorkOnItem( Item : TObject ); end; implementation { TMyThread } constructor TMyThread.Create; begin inherited Create( False ); // <-- NEIN, der Thread soll nie, nicht, niemals schlafen FCS := TCriticalSection.Create; FEvent := TEvent.Create( nil, False, False, '' ); FToDoList := TObjectList.Create( True ); end; destructor TMyThread.Destroy; begin {$IFDEF USE_TERMINATEDSET} // hier einfach nichts machen ... abwarten und Tee trinken {$ELSE} Terminate; FEvent.SetEvent; {$ENDIF} inherited; // jetzt alle Instanzen freigeben FToDoList.Free; FEvent.Free; FCS.Free; end; procedure TMyThread.DoWorkOnItem( Item : TObject ); begin // Hier irgendetwas mit dem Item machen end; procedure TMyThread.Execute; var LItem : TObject; begin inherited; // die übliche Schleife ... while not Terminated do begin // Warten, bis es etwas zu arbeiten gibt FEvent.WaitFor; // Wenn der Event gefeuert wurde, prüfen wir mal ob ... if not Terminated then begin // Item aus der ToDoListe holen LItem := GetItem; try // Mit dem Item arbeiten DoWorkOnItem( LItem ); finally // Item-Instanz freigeben LItem.Free; end; end; end; end; function TMyThread.GetItem : TObject; begin FCS.Enter; try // Item aus der ToDoListe entnehmen Result := FToDoList.Extract( FToDoList.First ); // Wenn dort nocht Items enthalten sind, dann setzen wir den Event auch wieder if FToDoList.Count > 0 then FEvent.SetEvent; finally FCS.Leave; end; end; {$IFDEF USE_TERMINATEDSET} procedure TMyThread.TerminatedSet; begin inherited; // Wenn Terminted, dann braucht hier keiner mehr warten FEvent.SetEvent; end; {$ENDIF} procedure TMyThread.WorkOnItem( Item : TObject ); begin FCS.Enter; try // Item in die ToDoListe einfügen FToDoList.Add( Item ); // und per Event den Thread aufwecken FEvent.SetEvent; finally FCS.Enter; end; end; end. ![]() |
AW: Arbeiten mit TThreadList
Ok. Vielen Dank für dein Beispiel. Die BeforeDestruction werd' ich einbauen.
Delphi-Quellcode:
destructor TD2007Thread.Destroy;
begin if (FThreadID <> 0) and not FFinished then begin Terminate; if FCreateSuspended then Resume; WaitFor; end; RemoveQueuedEvents(Self, nil); {$IFDEF MSWINDOWS} if FHandle <> 0 then CloseHandle(FHandle); {$ENDIF} {$IFDEF LINUX} // This final check is to ensure that even if the thread was never waited on // its resources will be freed. if FThreadID <> 0 then pthread_detach(FThreadID); sem_destroy(FCreateSuspendedSem); {$ENDIF} inherited Destroy; FFatalException.Free; RemoveThread; end; |
AW: Arbeiten mit TThreadList
Ein Problem sehe ich hier im Destructor
Delphi-Quellcode:
Das Problem kann hier auftauchen:
destructor TD2007Thread.Destroy;
begin if (FThreadID <> 0) and not FFinished then begin Terminate; if FCreateSuspended then Resume; WaitFor; // Diese Stelle ist problematisch end;
Delphi-Quellcode:
Denn nun wird zwar im Destructor korrekterweise das
var
LThread : TThread; begin LThread.Create( True ); LThread.Free; end; ![]() ![]() In neueren Delphi-Versionen wird genau nach dem
Delphi-Quellcode:
noch in Kombination mit
Resume
![]()
Delphi-Quellcode:
if FCreateSuspended or FSuspended then
Resume; while not FStarted do Yield; WaitFor; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:11 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