2017-04-02 33 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; 
相关问题