![]() |
AW: Freigabe Thread
Hallo,
Was ich in deinem Originalcode für kritisch halte ist die Sequenz aus .Terminate; gefolgt von .free; da der Aufruf von Terminate lediglich das Ende des Threads einleitet aber bei der Rückkehr der Thread ggf. noch läuft und du einen laufenden Thread frei gibst. Ich verwende steht's die Sequenz aus. .Terminate; .WaitFor; .free; Auch würde ich davon abraten den Thread direkt im .Execute freizugeben. Was du mit deinem OnReady Ereignis tust. André |
AW: Freigabe Thread
Ich würde in so einem Fall auch TTask.Run nehmen...
es sei den, Ich will nicht den Overhead und erzeuge mir vorab einen Thread. Diese kille ich am Ende des Programms. Der Thread wartet auch einen TEvent und verbraucht keine Taktzyklen, starten aber in wenigen Pico Sekunden. Dafür erzeuge ich ggf. eine Queue in die ich neue Werte schreibe und der Thread startet, wenn das passiert ist. Oder halt nur einen Wert. Also Werte an Thread übergeben, SetEvent aufrufen fertig. Wenn der Thread die Arbeit erledigt hat, legt er sich wieder schlafen... Oder ich nutze FreeOnTerminate und gebe dem Thread ein Notifyer Interface mit, dass dann die Werte halten kann, wenn der Thread schon lange tot ist. Zum Beispiel so:
Delphi-Quellcode:
Natürlich kann ich daraus auch einen INotify<T> und TWorker<T> machen und das dann für alle möglichen Typen verwenden.
program Project13;
{$APPTYPE CONSOLE} uses System.Classes , System.SysUtils , Windows ; Type INotify = Interface ['{27E27AAC-63A6-4289-8B58-BCD4039AAE6C}'] Procedure Ready(Value : Integer); End; TNotify = Class(TInterfacedObject,INotify) strict private Procedure Ready(aValue : Integer); private fValue : Integer; fOnReady : TProc<Integer>; public Constructor Create(aProc : TProc<Integer>); Destructor Destroy;override; end; TWorker = Class(TThread) Protected Procedure Execute;override; private fNotify : INotify; public Constructor Create(aNotify : INotify); End; { TNotify } constructor TNotify.Create(aProc: TProc<Integer>); begin Inherited Create; fOnReady := aProc; end; destructor TNotify.Destroy; begin fOnReady(fValue); inherited; end; procedure TNotify.Ready(aValue: Integer); begin fValue := aValue; end; { TWorker } constructor TWorker.Create(aNotify: INotify); begin fNotify := aNotify; FreeOnTerminate := true; inherited Create(false); end; procedure TWorker.Execute; begin Sleep(5000); fNotify.Ready(42); end; var Worker : TWorker; begin try Worker := TWorker.Create(TNotify.Create(Procedure (aValue : Integer) begin // Still Thread Context Writeln(aValue,' MainThread:',Windows.GetCurrentThreadId() = System.MainThreadID); end)); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end. In diesem Fall, würde ich den Execute Teil, ggf. Überschreiben. Mavarik :coder: |
AW: Freigabe Thread
TTask habe ich ehrlich gesagt noch nie genutzt. Müsste ich mir mal angucken.
Das Beispiel von Mavarik sieht mehr irgendwie zu "viel" aus. Da ist der einfache Thread mit seinem Create/Destroy und Execute für mich übersichtlicher, sicherlich aber Ansichtssache. |
AW: Freigabe Thread
Zitat:
Bleib bei deinem Thread der jetzt funktioniert und gut. Ansonsten sieht das mit dem TTask abgespeckt so aus. Dein Ready-Event packst du am Ende wie bei deinem Thread selber rein
Delphi-Quellcode:
TTask.Run(
procedure begin // Code end); |
AW: Freigabe Thread
Zitat:
Zitat:
zu erhalten, wenn der Thread fertig ist. Normalerweise mache ich das noch aufwendiger! Folgendes Beispiel: In einem Form soll eine Aufgabe im Hintergrund ausgeführt werden... Klar kann man das als "Schön-Wetter-Code" schreiben mit:
Delphi-Quellcode:
1. Was ist, wenn der Sleep eine Abfrage auf einen WebServer ist, der nicht wiederkommt oder ein Timeout hat von 5 Min.
Procedure TForm1.Button1OnClick(Sender : TObject);
begin Button1.Enabled := false; TTask.Run(Procedure begin Sleep(5000); // of was richtiges. TThread.Queue(Nil,Procedure begin Edit1.Text := 'Thread ist fertig und hat: 42 ermittelt'); Button1.Enabled := true; end); end); end; 2. Was ist, wenn das eine lange SQL-Abfrage ist die einfach ewig dauert? Problem - der Button, geht nicht wieder auf Enabled... Toll.. Was aber wenn der User das Fester bereits wieder geschlossen hat? Peng Exeption und die fängt auch erstmal keine ab... Man kann natürlich da noch ein try except drum setzen... OK - Dann das Beispiel mit einem eigenen TThread... Was ist wenn der Thread im Execute etwas aufruft, das nicht wieder kommt und damit steht? Richtig, ein TThread.Destroy signalisiert Terminate aber das wir leider nicht ausgeführt. Wenn also das Thread im FormOnDestroy oder wo auch immer freigegeben werden soll, bleibt das Fenster offen und die Anwendung steht. Ich brauche also wenigstens ein Handle, das OutOfScope geht, wenn ich das Form schließe. Das OutOfScope darf nicht versuchen den Thread frei zu geben, sonst steht die Anwendung wieder. Ich nehme das "nur" als signal, um den OnFinish-Class back mitzuteilen, dass er nicht mehr aufs Form zugreifen darf. Und der Thread? - Naja, der lebt als tote Instance solange, bis die Routine im Execute mal zurück kommt oder das Programm beendet wird. Das kann ich auch 10x versuchen... Die wenigen bytes stören mich nicht. Leider gibt es - außer mit einem OutOfProcess Server keine andere Möglichkeit den Thread zu zerstören. Aber ein OutOfProcess Thread wäre dann hierfür vielleicht doch etwas "zu viel"... Mavarik :coder: |
AW: Freigabe Thread
Zitat:
Während des Queue kann das Fenster dann anschließend nicht mehr verschwinden. (außer man hat ein Application.ProgressMessage, einen Dialog oder Ähnliches darin) Bei Dateioperationen auf eine Netzwerkfreigabe, da kann es auch schonmal ewig hängen. Da kann man entweder Asynchron arbeiten, oder auch von außerhalb via ![]() Auch viele Netwerkkomponenten und auch DB-Komponenten haben eine Funktion um von außerhalb Operationen in einem anderen Thread abzubrechen. Falls es keinen Timeout gibt, oder der nicht immer funktioniert, kann man z.B. beim Schließen des Fensters dennoch einen Abbruch einleiten. Den Thread selbst aber hart abzuschießen ( ![]() |
AW: Freigabe Thread
Zitat:
Weil ein Assigned(Self) geht logischerweise nicht. Zitat:
Zitat:
sein eigenes Memory Management hat und ggf. den Thread killt und den Speicher aufräumt. Mavarik :coder: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:12 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