在这个例子中,我们如何确保线程实例已被释放?当Thread.FreeOnTerminate = true并且你在Thread.OnTerminate事件中爆炸时,线程实例会发生什么?线程是否是孤立的,除非你处理异常并在OnTerminate中释放线程explicitey?
// 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;
答案 0 :(得分:6)
您应该处理OnTerminate处理程序中的所有异常,因为未处理的异常将导致不释放该线程的实例(请参阅Classes.ThreadProc
实现)。
只需将处理程序的正文放在try
.. except
中,并处理所有异常。
但是''保证AV'的例子是错误的:如果实例为零,Free
不会导致AV。
答案 1 :(得分:3)
OnTerminate
处理程序通过Synchronize
在主线程中执行。如果从Synchronize
抛出异常,它将在主线程中被抑制并被传递(通过AcquireExceptionObject
)到调用线程,在那里它再次被引发。在我所指的ThreadProc
版本中(the open-source Kylix version from 2001),异常没有被处理,因此异常传播到操作系统,调用线程程序。 <{1}}对象不会被释放。
不要从析构函数中抛出异常的建议也明显适用于其他类型的清理例程。
答案 2 :(得分:0)
设置FreeOnTerminate会导致问题。这是因为它释放了一次线程因为构造函数失败然后再次因为FreeOnTerminate被设置而被释放。
解决方案:将其移至Execute方法或在构造函数的末尾设置它,其中任何有风险的活动已经安全完成......
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。