【问题标题】:Delphi TThread handle errorDelphi TThread 句柄错误
【发布时间】:2018-06-30 16:52:58
【问题描述】:

我正在阅读“Delphi 高性能”,但我缺少一些东西。将此代码作为测试:

type TTest = class(TThread)
  private
    amemo: TMemo;
  public
    constructor Create(ss: boolean; memo: TMemo);
  protected
    procedure Execute; override;
end;

constructor TTest.Create(ss: boolean; memo: TMemo);
begin
  inherited Create(ss);
  FreeOnTerminate := true;
  amemo := memo;
end;

procedure TTest.Execute;
var i: uint32;
begin
  inherited;
  i := 0;

  while not Terminated do
    begin
      Inc(i);
      Synchronize(procedure
                  begin amemo.Lines.Add(i.ToString) end);
      Sleep(1000);
    end;

end;

很简单,这个线程会在备忘录中打印一些数字。我启动了暂停的线程,所以我必须调用这段代码:

procedure TForm1.Button1Click(Sender: TObject);
begin
  thread := TTest.Create(true, Memo1);
  thread.Start;
end;

我总是停止调用thread.Terminate; 的线程,但阅读本书我看到 Primoz 停止了这样的线程:

procedure TForm1.Button2Click(Sender: TObject);
begin
  thread.Terminate;
  thread.WaitFor; //he adds this method call
  //FreeAndNil(thread)
  //there is the above line as well in the code copied from the book but I have removed it since I have set FreeOnTerminate := true (so I dont have to worry about freeing the obj).
end;

此时,如果我只使用 Terminate 运行代码,我没有问题。如果我使用 Terminate + WaitFor 运行代码,我会收到此错误:

我也阅读了更多关于 delphi 的代码,我看到 Nick Hodges 只是拨打了Terminate; 的电话。调用Terminate; 是否足以安全地停止线程?请注意,我设置了FreeOnTerminate := true,所以我关心对象的死亡。终止应该停止执行(里面是什么执行),所以它应该是这样的:

  • 通话终止
  • 执行停止
  • 线程停止执行
  • 线程现在是空闲的 (FreeOnTerminate := true)

请告诉我我错过了什么。


注意。 在书中线程没有FreeOnTerminate := true。所以需要手动释放线程;我想这就是他打电话的原因

thread.Terminate;
thread.WaitFor;
FreeAndNil(thread)

我同意 Terminate(停止 thread= 和 FreeAndNil(手动释放对象)但是 WaitFor?

【问题讨论】:

  • 一旦你启动了一个 FreeOnTerminate 为 true 的线程,那么你就不能再次使用对该线程的引用,因为你不能保证它是有效的。
  • @DavidHeffernan 我想我明白了。当我调用 thread.Terminate;线程终止,然后,由于 FreeOnTerminate 为真,对象被释放。由于对象是免费的,因此调用 WaitFor 当然不会起作用。 (这就是你所说的)
  • 附带说明,您不应该在Execute 中调用inherited
  • WaitFor() 不应与 FreeOnTerminate=True 一起使用,因为线程句柄在线程对象被释放时关闭,这就是导致“句柄无效”异常的原因。 FreeOnTerminate=True 应该只用于“一劳永逸”类型的线程。
  • @Craig 实际上,在 override 尤其是 abstract 方法中排除 inherited 应该非常简单。编译器忽略这种情况的事实告诉我已经实现了解决方法而不是实际修复:-/

标签: delphi delphi-10.2-tokyo


【解决方案1】:

请告诉我我错过了什么。

FreeOnTerminate 的文档明确指出您不能在Terminate 之后以任何 方式使用线程。

这包括你的WaitFor 调用,它可以在一个可能已经释放的对象上工作。这种释放后使用可能会触发上述错误,以及其他更“有趣”的行为。

【讨论】:

  • 文档太宽松了。出于任何原因,您无法真正访问FreeOnTerminate=True 线程。在您根本没有机会调用Terminate 之前,线程可能会自行终止(崩溃等)。您应该仅将FreeOnTerminate=True 用于启动它们后您不关心访问的“start-and-forget”线程。但是,一旦您出于任何原因需要访问它们,FreeOnTerminate=True 的使用就会变得很危险
猜你喜欢
  • 1970-01-01
  • 2017-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-19
相关资源
最近更新 更多