2014-03-12 81 views
1

当我停止线程'srch_slave_thread'并将终止标志设置为true时,(srch_slave_thread.terminate)释放线程停止在析构函数中的'inherited'行,为什么?它是一个等待它挂起?如果我在析构函数中注释掉“继承”,则线程停止并释放它自己。线程终止(再次...)

取出'继承'并调试代码后:为什么线程在调用析构函数后跳转到DoTerminate方法?

谢谢。

Tsrch_slave_thread = class(TThread) 
private 
    FSW: TStopWatch; 
protected 
    procedure Execute; override; 
public 
    SimpleEvent: TSimpleEvent; 
    procedure DoTerminate; override; 
    ... 
    constructor Create; 
    destructor Destroy; override; 
end; 

创建一个事件obj。在构造函数>>

constructor Tsrch_slave_thread.create; 
begin 
    inherited create(true); 
    Fsw := TStopWatch.Create; 
    SimpleEvent := TSimpleEvent.Create; 
end; 

在调用析构函数之后跳转到这里? >>

procedure Tsrch_slave_thread.DoTerminate; 
begin 
    inherited; 
    self.simpleEvent.SetEvent; 
end; 

危在旦夕在析构函数继承>>

destructor Tsrch_slave_thread.destroy; 
begin 
    self.SimpleEvent.free; 
    inherited; 
end; 

这里创建线程>>

function TMaster.th_slvsearch_start: integer; 
begin 
    if not Assigned(Fslave_search_thread) then begin 
    Fslave_search_thread := TFslave_search_thread.create; 
    ... 
    end 
    else begin 
    ... 
    exit; 
    end; 
    with Fslave_search_thread do 
    begin  
    master := self; 
    master_HWND := self.fMsgHandlerHWND; 
    FreeOnTerminate := false; 
    OnTerminate := slvsrch_termination; 
    start;   
    end; 
end; 

回采线程开始在这里>>

procedure TMaster.th_slvsearch_stop; 
begin 
    Fslave_search_thread.Terminate; 
end; 

主题.Execute >>

procedure Tsrch_slave_thread.Execute; 
var 
    text_orig: string; 
    activesearch: integer; 
begin 
    FSW.Start; 
    while not terminated do begin 
    activesearch := master.CMD_LISTCNT; 
    //stopper refresh 
    synchronize(procedure begin   
     with self.master do 
      Fmasternode.text := FmasterDat.MstrName + ' (' + floattostr(Fsw.ElapsedMilliseconds/1000) + 'sec - Searching)'; 
    end); 
    if (SimpleEvent.WaitFor(2000) <> wrTimeOut) or (activesearch <> 1) then break; 
    end; 
    FSW.Stop; 
end; 

OnTerminate事件处理>>

procedure TMaster.slvsrch_termination(Sender: TObject); 
begin 
    if Assigned(Fslave_search_thread) then 
    begin 
    self.FLastSearchTime := Fslave_search_thread.FSW.ElapsedMilliseconds/1000; 
    Fslave_search_thread.Free; 
    Fslave_search_thread := nil; 
    self.Factive_slv_search := 0; 
    end; 
    ... 
end; 
+0

*“为什么线程在调用析构函数后跳转到DoTerminate方法?”*因为有人应该说线程终止,如果它不是明确的你,它是设置终止标志的析构函数。 – TLama

+0

@TLama,是的,但我用srch_slave_thread.terminate设置标志 – grinner

回答

6

你从它的OnTerminate事件处理程序调用Thread对象Free。单单是一个错误,因为在发射事件的时候你不能释放一个对象,因为当事件返回时,你现在正在一个已被销毁的对象中执行代码。

但这不是你的直接问题。由于致电WaitForTThread.Destroy,您已将线程锁定。线程无法完成,因为它自己在等待。线程调用堆栈上看起来是这样的:

 
Synchronize(CallOnTerminate) 
DoTerminate 
ThreadProc 

所以线程等待主线程上执行完毕CallOnTerminate。在主线程中,您的OnTerminate处理程序内部是对Free的呼叫。这反过来导致致电WaitFor。因此主线程正在等待线程完成。那是你经典的僵局。线程A等待线程B,线程B等待线程A.

故事的寓意:从未在其OnTerminate事件处理程序中的线程上调用Free

的解决方案可能是设置FreeOnTerminateTrue并在OnTerminate处理程序中设置Fslave_search_threadnil

+0

这不是我第一次犯这个错误,但希望它是最后一次。谢谢。 – grinner

+0

现在我的问题是,如果我关闭应用程序,生成一些AV。 线程的obj引用是另一个对象(TMaster)的字段。当我关闭应用程序时,我释放了所有的主人。在TMaster的析构函数中,我设置了线程的终止标志(如果之前分配了线程)。这有什么不对? – grinner

+0

好的。那么,我想你会做一个SSCCE,并发布一个新的问题。 –