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;