释放线程时的死锁

时间:2014-06-13 12:21:22

标签: multithreading delphi deadlock

在释放工作线程时遇到一些问题,我只是不明白为什么在线程的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;

1 个答案:

答案 0 :(得分:4)

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

这就是死锁。它的进展如下:

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