在释放工作线程时遇到一些问题,我只是不明白为什么在线程的OnTerminate事件处理程序(TMaster.slvsrch_termination)
中释放线程的死锁。
我使用postmessage而不是在线程执行同步来同步一些VCL控件,只是为了避免死锁。
procedure Tsrch_slave_thread.Execute;
var
activesearch: integer;
begin
activesearch := 1;
FMaster.CMD_SEARCH;
FSW.Start;
while not terminated do begin
postmessage( FDevTree_HWND, WM_STOPPER_REFRESH, trunc(Fsw.ElapsedMilliseconds / 1000), integer(FMasterNode) );
//
if (SimpleEvent.WaitFor( SEARCH_DELAY_SEC ) <> wrTimeOut) or (activesearch <> 1) then break;
activesearch := Fmaster.CMD_LISTCNT;
FSW.Stop;
end;
end;
procedure Tsrch_slave_thread.DoTerminate;
begin
inherited;
self.simpleEvent.SetEvent;
end;
线程的FreeOnTerminate属性设置为false:
...
Fslave_search_thread: Tsrch_slave_thread;
...
Fslave_search_thread.FreeOnTerminate := false
Fslave_search_thread.OnTerminate := slvsrch_termination;
...
procedure TMaster.slvsrch_termination(Sender: TObject);
begin
...
if Assigned(Fslave_search_thread) then
begin
Fslave_search_thread.free; //Deadlock, why?
Fslave_search_thread := nil;
end;
...
end;
答案 0 :(得分:4)
发生死锁是因为线程的析构函数在线程上等待。它会调用WaitFor
来执行此操作。线程的析构函数是从slvsrch_termination
调用的。这是线程的OnTerminate
事件处理程序。并且OnTerminate
事件处理程序在主线程中执行,因为它们是通过调用Synchronize
来调用的。
这就是死锁。它的进展如下:
Execute
完成,线程运行其终止代码。Synchronize
来等待主线程。WaitFor
。现在主线程正在等待从属线程。步骤2和3是你的僵局。
除了死锁之外,从自己的OnTerminate
处理程序中释放从属线程实例也是一个错误。查看线程过程中的代码:
FreeThread := Thread.FFreeOnTerminate;
Thread.DoTerminate;
Thread.FFinished := True;
通过调用OnTerminate
调用您的DoTerminate
处理程序。返回时,Thread
已被销毁,但代码仍然可以访问它。您还可以查看以下代码:
procedure Tsrch_slave_thread.DoTerminate;
begin
inherited;
self.simpleEvent.SetEvent;
end;
inherited
调用OnTerminate
处理程序。这释放了实例。然后你访问实例。
底线是你不能从其OnTerminate
处理程序释放线程。