2014-03-12 77 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,併發佈一個新的問題。 –