如果FreeOnTerminate = true并且在OnTerminate中抛出异常,那么线程会发生什么?

时间:2011-05-18 16:21:49

标签: multithreading delphi

在这个例子中,我们如何确保线程实例已被释放?当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;

3 个答案:

答案 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。