delphi – 线程错误:当尝试释放挂起的线程时,句柄无效(6)

在给定的示例中,我在调用AThread.Free时收到异常.

program Project44;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes, Windows;

type
  TMyException = class(Exception);

var
  AThread: TThread;
begin
  AThread := TThread.Create(True);
  try
    AThread.FreeOnTerminate := True;
    //I want to do some things here before starting the thread
    //During the setup phase some exception might occur, this exception is for simulating purpouses
      raise TMyException.Create('exception');
  except
    AThread.Free; //Another exception here
  end;
end.

我有两个问题:

>在给定的示例中,如何释放AThread的TThread实例?
>我不明白,为什么TThread.Destroy在销毁之前调用Resume.这有什么意义?

最佳答案
您不能将FreeOnTerminate设置为True并在线程实例上调用Free.你必须做一个或另一个,但不是两个.因为它代表你的代码破坏线程两次.你必须永远不要销毁一个对象两次,当然,当析构函数第二次运行时,会发生错误.

这里发生的事情是,由于您创建了线程暂停,因此在您明确释放线程之前不会发生任何事情.当你这样做时,析构函数恢复线程,等待它完成.然后,这会导致Free被再次调用,因为您将FreeOnTerminate设置为True.第二次调用Free会关闭句柄.然后返回到线程proc并调用ExitThread.这会失败,因为线程的句柄已经关闭.

正如Martin在评论中指出的那样,你不能直接创建TThread,因为TThread.Execute方法是抽象的.此外,您不应使用已弃用的Resume.使用“开始”开始执行挂起的线程.

我个人不喜欢使用FreeOnTerminate.使用此功能会导致线程在创建它的其他线程上被销毁.当您想要忘记实例引用时,通常会使用它.这使您不确定在进程终止时线程是否已被销毁,或者在进程终止期间是否终止并释放自身.

如果你必须使用FreeOnTerminate,那么你需要确保在将FreeOnTerminate设置为True后不要调用Free.因此,显而易见的解决方案是在调用Start之后立即将FreeOnTerminate设置为True,然后忘记线程实例.如果在准备好开始之前有任何例外,那么你可以放心地释放线程,因为FreeOnTerminate在那时仍然是False.

Thread := TMyThread.Create(True);
Try
  //initialise thread object
Except
  Thread.Free;
  raise;
End;
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;

更优雅的方法是将所有初始化移动到TMyThread构造函数中.然后代码看起来像这样:

Thread := TMyThread.Create(True);
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;

转载注明原文:delphi – 线程错误:当尝试释放挂起的线程时,句柄无效(6) - 代码日志