2011-05-18 37 views
2

給出這個例子,我們如何確保線程實例已經被釋放? Thread.FreeOnTerminate = true時線程實例會發生什麼情況,並在Thread.OnTerminate事件中爆發?線程是否孤立,除非您處理異常並釋放OnTerminate中的線程解釋?
如果FreeOnTerminate = true並且在OnTerminate中拋出異常,線程會發生什麼?

// Thread constructor 

constructor TMyThread.Create(CreateSuspended: Boolean); 
begin 
    inherited Create(CreateSuspended); 
    Self.FreeOnTerminate := True; 
end; 

// TMyThread OnTerminate event 

procedure TMyThread.OnTerminate(Sender: TObject); 
var o: TObject;  
begin 
    o:=nil; 
    showmessage(o.classname); // guaranteed AV 
end; 
+3

空指針上沒有AV。銷燬AV會在一個零指針上。事實上,Free對於nil指針來說是行之有效的,事實上它總是使用Free而不是直接使用Destroy。 – 2011-05-18 16:51:14

+0

@majan - 的確如此。修正了。 – Vector 2011-05-19 01:51:30

回答

6

你應該處理您OnTerminate處理所有的異常,因爲未處理的異常會導致該線程的實例將不會被釋放(見Classes.ThreadProc實現)。 只需在try .. except中附上您的處理程序主體並處理所有異常。

但是你的'保證AV'的例子是錯誤的:如果實例爲零,Free不會導致AV。

+0

當我發佈了這個問題後,我意識到我應該檢查VCL,並且我也看到了你引用的Classes.ThreadProc實現中的代碼(在D5和XE中),所以我編碼相應。 TNX。 (修正了AV例子)。但是令我驚訝的是,他們沒有將這段代碼放在finally塊中,以便在freeonterminate = true時釋放線程對象,無論OnTerminate中發生了什麼。任何解釋爲什麼它不是這樣編碼的? – Vector 2011-05-19 02:51:21

3

OnTerminate處理程序在主線程中通過Synchronize執行。如果從Synchronize拋出異常,它會在主線程中被抑制,並通過AcquireExceptionObject轉移到調用線程,並在該線程中再次提升。在ThreadProc的版本中,我指的是(the open-source Kylix version from 2001),異常沒有得到處理,所以異常傳播到稱爲線程過程的OS中。 TThread對象不會被釋放。

不要從析構函數中拋出異常的建議顯然也適用於其他類型的清理例程。

+0

與Delphi 2009相同 - OnTerminate中的異常沒有得到處理,TThread對象也沒有被釋放。 – kludg 2011-05-18 16:55:05

+0

我並沒有考慮把自己扔在那裏,但它作爲一個新的增強運行在一個非常古老的,大型的,高度耦合的應用程序的背景下,並且帶有層次的繼承和嵌套的'with'塊,所以我永遠不會相當確定我什麼時候會在哪裏被咬。就在今天下午,我發現了一個陰險的異常食用者,引起了我很大的悲痛...... – Vector 2011-05-19 06:09:30

0

如果構造函數稍後失敗,則FreeOnTerminate會導致問題。這是因爲它釋放了一次線程,因爲構造函數失敗,然後又因爲FreeOnTerminate被設置了。

的解決方案:將其移動到執行方法或其中任何危險的活動已經完成安全的構造結束設置...

TMyThread = class(TThread) 
    private 
    m_bFreedAlready:boolean; 
    protected 
    procedure Execute; override; 
    public 
    constructor Create; 
    destructor Destroy; override; 
    end; 

constructor TMyThread.Create; 
begin 
    inherited Create(false); 

    FreeOnTerminate:=true; 

    // something went wrong 
    raise Exception.Create('Error Message'); 
end; 

destructor TMyThread.Destroy; 
begin 
    if m_bFreedAlready then 
    MessageBox(0, 'error', 'oops; freed a second time--soon we will have an error!', 0); 

    m_bFreedAlready:=true; 

    inherited; 
end; 

procedure TMyThread.Execute; 
begin 
    inherited; 

end; 

使用XE3。

+0

這不是一個答案 - 它是(一行)評論。請發表評論。 – Vector 2015-04-14 15:54:47

+0

我想讓它成爲一個評論,但我會認爲一個評論會破壞代碼的可讀性。如果這對你來說是一個「大問題」,我建議你刪除我的寶貴意見。 – 2015-04-14 18:04:08

+0

重點不在於OnTerminate。是的,我測試了它。 – 2015-04-14 22:46:15

相關問題