2017-04-02 2 views
5

Momentan verwende ich zusätzlichen Thread, um Speicher nach Thread freizugeben. Bevor Sie fragen. Nein, ich kann FreeOnTerminate nicht verwenden: = true, weil ich .waitfor brauche. Ich brauche auch FreeAndNil(), weil ich nur auf diese Weise überprüfen kann, ob der Thread mit Assigned() läuft. BeispielcodeWie FreeAndNill() nach der Beendigung des Threads automatisch ausgeführt wird

procedure TForm1.Button1Click(Sender: TObject); 
begin 

    SupervisorThread:= TSupervisorThread.Create(True); 
    SupervisorThread.FreeOnTerminate:=false; //MUST BE FALSE! 
    SupervisorThread.Priority := tpNormal; 
    SupervisorThread.Resume; 

end; 

procedure TSupervisorThread.Execute; 
begin 

    CleaningThread:= TCleaningThread.Create(True); 
    CleaningThread.FreeOnTerminate:=true; 
    CleaningThread.Priority := tpNormal; 
    CleaningThread.Resume; 

    //some loops here 

end; 

procedure TCleaningThread.Execute; 
begin 

    if Assigned(SupervisorThread)=true then 
    begin 
    SupervisorThread.WaitFor; 
    FreeAndNil(SupervisorThread); 
    end; 

end; 

procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean); 
begin 

    if Assigned(SupervisorThread)=false then CanClose:=true 
    else 
    begin 
    CanClose:=false; 
    ShowMessage('Cannot close form because SiupervisorThread is still working'); 
    end; 

end; 
+2

Verwenden Ereignisse zu signalisieren, äh, Ereignisse –

+0

Wenn die einzige Sache, die Sie wissen wollen, ob der Thread abgeschlossen ist, weisen Sie einen 'OnTerminate' Handler zum Thema. –

+0

Ich muss darauf hinweisen, dass ein Thread, der von einem anderen Thread mit "SupervisorThread.WaitFor;" blockiert wird, scheint ein wenig sinnlos als Thread. Erinnern Sie sich, dass der Punkt von Threads Code _concurrently_ ausführen soll. Ihr Beispiel wirft die Fragen auf: Warum können Sie Cleaning nicht einfach am Ende des Supervisors ausführen? Warum müssen Sie das Reinigungsobjekt im Vordergrund erstellen? Kannst du nicht warten bis Supervisor fertig ist? Was passiert, wenn Sie die Reinigung beenden möchten? - Sie können nicht, weil es nicht in einer 'while not terminated' Schleife ist. –

Antwort

4

Verwenden Sie das TThread.OnTerminate Ereignis:

private 
    procedure DoTerminateEvent(Sender: TObject); 

var 
    isRunning: Boolean; 

procedure TForm2.DoTerminateEvent(Sender: TObject); 
begin 
    isRunning := False; 
end; 

procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean); 
begin 
    if (isRunning) then 
    begin 
    CanClose := false; 
    ShowMessage('Cannot close form because SupervisorThread is still working') 
    end else 
    CanClose := true; 
end; 

Stellen Sie den OnTerminate Handler, wenn der Thread erstellen:

SupervisorThread := TSupervisorThread.Create(True); 
... 
SupervisorThread.OnTerminate := DoTerminateEvent; 
SupervisorThread.Resume; 

Oder geben sie als Parameter an den Konstruktor der Thread:

TSupervisorThread = class(TThread) 
public 
    constructor Create(OnTerminatEvent: TNotifyEvent); 
end; 

procedure TThreadCustom.Create(OnTerminateEvent: TNotifyEvent); 
begin 
    inherited Create(True); 
    OnTerminate := OnTerminateEvent; 
end; 

SupervisorThread := TSupervisorThread.Create(DoTerminateEvent); 
+0

Mein Delphi sagt "NOT GENUG ACTUAL PARAMETERS" hier SupervisorThread.OnTerminate: = (DoTerminateEvent); –

+2

@Atak_Snajpera Das liegt daran, dass der Code in der Frage falsch ist. Wenn Sie die Dokumentation lesen und ein wenig darüber nachdenken, könnten Sie herausfinden, was falsch war. Hör nicht auf, selbst zu denken. –

+0

Ich habe es vorher ohne Klammern versucht, aber ich habe "INCOMPATIBLE TYPES: 'Methodenzeiger und reguläre Prozedur' –

1

können Sie die TThread.OnTerminate Ereignis verwenden, um festzustellen, wann ein Thread ausgeführt wird beendet, zB:

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    if not Assigned(SupervisorThread) then 
    begin 
    SupervisorThread:= TSupervisorThread.Create(True); 
    SupervisorThread.FreeOnTerminate := False; 
    SupervisorThread.Priority := tpNormal; 
    SupervisorThread.OnTerminate := SupervisorThreadTerminated; 
    SupervisorThread.Resume; 
    end; 
end; 

procedure TForm1.SupervisorThreadTerminated(Sender: TObject); 
begin 
    SupervisorThread := nil; 
end; 

Dies ist jedoch einige Probleme schafft. Es entsteht ein Race Condition, da der Reinigungsfaden auf den Zeiger SupervisorThread wirkt, der jederzeit verschwinden kann, während der Reinigungsfaden noch läuft. Und es erzeugt einen Speicherverlust, da Sie das Objekt SupervisorThread nach dem Beenden noch freigeben müssen, aber Sie können dies nicht direkt im Handler OnTerminate tun.

Eine bessere Lösung würde sich überhaupt nicht auf den Zeiger SupervisorThread verlassen.

var 
    SupervisorTerminated: TEvent; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    SupervisorTerminated := TEvent.Create(nil, True, True, ''); 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    if Assigned(SupervisorThread) then 
    begin 
    SupervisorThread.Terminate; 
    while SupervisorTerminated.WaitFor(1000) = wrTimeout do 
     CheckSynchronize; 
    end; 
    SupervisorTerminated.Free; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    if not Assigned(SupervisorThread) then 
    begin 
    SupervisorThread := TSupervisorThread.Create(True); 
    SupervisorThread.FreeOnTerminate := True; 
    SupervisorThread.Priority := tpNormal; 
    SupervisorThread.OnTerminate := SupervisorThreadTerminated; 
    SupervisorTerminated.ResetEvent; 
    SupervisorThread.Resume; 
    end; 
end; 

procedure TForm1.SupervisorThreadTerminated(Sender: TObject); 
begin 
    SupervisorThread := nil; 
    SupervisorTerminated.SetEvent; 
end; 

procedure TCleaningThread.Execute; 
begin 
    SupervisorTerminated.WaitFor(INFINITE); 
end; 

procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean); 
begin 
    CanClose := (SupervisorTerminated.WaitFor(0) = wrSignaled); 
    if not CanClose then 
    ShowMessage('Cannot close form because Supervisor Thread is still working'); 
end; 
Verwandte Themen