在 Delphi 中,检查具有 FreeOnTerminate = True 的非挂起创建的 TThread 是否仍在执行的正确方法是什么?


所以我创建了一个类:TWorkerThread = class(TThread)。在TWorkerThread构造函数中,我设置了FreeOnTerminate := True

然后,我在TForm中添加了一个私有的Worker变量。当我为Worker实例化TWorkerThread时,我总是使用CreateSuspended := False

一旦启动,我唯一需要与线程进行的交互就是取消进程(Terminate(并检查进程是否结束(该检查是基于用户事件的(。

要检查线程是否仍处于活动状态,我需要:

if (Self.Worker <> nil) and (not Self.Worker.Finished) then
//Still active

这似乎很好,但我担心在某个时候TWorkerThread会是<> nil,但仍然是.free(记住TWorkerThread都是FreeOnTerminate := True(。当CCD_;自毁;一旦终止,它们总是变成nil吗?如果没有,我该如何处理(以避免访问违规(?

还有一件事,如果一个Worker在它的形态破坏上是活动的,我会这样做:

if (Self.Worker <> nil) and (not Self.Worker.Finished) then
begin
Self.Worker.Terminate;
//wait here for completion
end;

Terminate之后,如果我执行WaitFor,我将获得访问冲突(因为自毁(。我应该在这里强制等待吗?最好的方法是什么?

这是我在Delphi中首次正确使用TThread。为了清楚起见,上面的代码是我所做工作的一个精简版本。

在Delphi中检查是否创建了非挂起FreeOnTerminate=True的TThread仍在执行?

没有。

一旦自毁线程启动,就不允许再从代码外部接触持有此类线程的引用,因为该引用随时可能变得过时。

在某些情况下(如果在自定义线程类中没有修改DoTerminate中处理OnTerminate调用的逻辑(,您可以安全地从OnTerminate事件处理程序访问线程引用。然而,这并不能帮助您解决问题,因为您不能等待自毁线程。在Windows上,这样的代码会导致可以捕获和处理的异常,但在其他平台上,它会导致未定义的行为和随机死锁。但即使在Windows上编写这样的代码也是不可取的。

若您需要检查线程的状态、取消线程或等待线程,则不能使用自毁线程。时期(对于那些可能反对之前说法的人来说,是的,在某些情况下,其中一些事情是可能的,但它们通常会导致开枪自杀(。

您可以将以下工作流与TWorkerThread一起使用,前提是在线程构造函数中将FreeOnTerminate保留在False上,并构造未暂停的线程。以下所有方法都必须从主线程调用,以避免Worker引用上的竞争条件。当你的表单打开时,有一个额外的线程什么都不做不会给你带来任何麻烦。

procedure TMyForm.StartWorker;
begin
FreeAndNil(Worker); // or if Assigned(Worker) then Exit;
Worker := TWorkerThread.Create;
end;
procedure TMyForm.CancelWorker;
begin
// this will initiate thread termination and waiting
FreeAndNil(Worker);
end;
procedure TMyForm.Destroy;
begin
// technically we could only use Free here, 
// but since other code requires niling the reference this is more consistent 
FreeAndNil(Worker);
inherited;
end;

最新更新