2014-06-13 86 views
2

解决了一个工作线程有一些问题,我只是不明白为什么释放线程的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; 

回答

4

发生死锁,因为线程线程的析构函数等待。它叫WaitFor这样做。线程的析构函数从slvsrch_termination调用。这是线程的OnTerminate事件处理程序。并且OnTerminate事件处理程序在主线程中执行,因为它们是通过调用Synchronize调用的。

这里是死锁。它的进展是这样的:

  1. 线程Execute完成,线程运行其终止代码。
  2. 线程终止代码被同步到主线程上。此时,从线程正在通过调用Synchronize来等待主线程。
  3. 在主线程上运行的线程终止代码破坏了从线程。这导致线程上的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处理程序中释放线程。

+0

怪异的......我得到了橙色的“一个新的答案已发布......”酒吧字面上,因为我正在点击答案按钮,但你的答案出现了比我早10分钟的时间戳。大卫,你的魔力永远不会惊叹! –

+0

但他没有试图从同一线程的OnTerminate处理程序中释放该线程。据我所知它是2个不同的线程,他从主线程的OnTerminate事件释放slave线程。我错过了什么? –

+0

@J ...我怀疑时删除了答案的原始版本。我想知道是否错误地调用'Free'会导致死锁。尽管这显然是错误的,但我认为不是。我认为僵局就在这个事件上。 –