2011-05-18 36 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

相关问题