2017-04-02 64 views
5

目前我正在使用額外的線程來很好地釋放線程後的內存。 在你問之前。不,我不能使用FreeOnTerminate:= true,因爲我需要.waitfor。 我也需要FreeAndNil(),因爲只有這樣我才能檢查線程是否使用Assigned()運行。示例代碼。創建線程時如何在線程終止後自動執行FreeAndNill()

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; 

設置OnTerminate處理:

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

使用的事件信號,呃,事件 –

+0

如果你想的唯一的事情就是要知道如果線程完成後,分配'OnTerminate'處理器到線程。 –

+0

我必須指出,一個線程被'SupervisorThread.WaitFor;'所阻塞的另一個線程看起來有點毫無意義。記住線程的要點是允許代碼執行_concurrently_。您的示例引發了以下問題:爲什麼不能在Supervisor結束時運行清理?爲什麼你必須在前面創建清潔對象;你能等到主管完成嗎?如果你想「終止」清洗會發生什麼? - 你不能,因爲它不是在'Terminated'循環中。 –

回答

4

使用TThread.OnTerminate事件

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

或者,作爲參數傳遞給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

我的delphi在這裏說「不夠實際的參數」 SupervisorThread.OnTerminate:=(DoTerminateEvent); –

+2

@Atak_Snajpera這是因爲問題中的代碼是錯誤的。如果你想閱讀文檔,想一想,你就可以弄清楚什麼是錯的。不要停下來想想自己。 –

+0

我以前沒有使用括號,但我得到了 「不兼容的類型:」方法指針和常規過程' –

1

可以使用TThread.OnTerminate事件當一個線程運行完成檢測,如:

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; 

然而,這產生了一些問題。由於清潔線作用在SupervisorThread指針上,因此清潔線程仍在運行時,該指針可能隨時消失,因此會產生競爭狀態。它會產生內存泄漏,因爲在終止對象後仍然需要釋放對象,但不能直接在OnTerminate處理程序中執行此操作。

更好的解決方案根本不依賴於指針SupervisorThread

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; 
相關問題