问题描述
背景
使用 TThread.CreateANonymousThread(aProc:TProc)
我可以创建一个线程,在线程终止后销毁线程对象。 (或者,对于线程对象,将 FreeOnTerminate
设置为 true
)。这允许线程启动器例程完成并超出范围,而线程继续运行。 (这就是我要找的)
procedure StartProcess
begin
var lTask:=TThread.CreateAnonymousThread(
procedure
begin
... Do lengthy thread stuff here
end
);
...
lTask.Start;
end;
问题出现了,TTask.Create 返回一个 ITask
接口,当线程发起者代码删除其上下文(RefCount
下降到 0
-> {{1} } 被调用),导致线程生成一个 AV。
Destroy
在 procedure StartProcess
begin
var lTask:=TTask.Create(
procedure
begin
... Do lengthy thread stuff here
end
);
...
lTask.Start;
end; /// past this point,the subthread wil crash because the underlying task object is destroyed
的情况下,我们有一个名为 OmniThread
的解决方案,可避免任务对象在完成之前被销毁。
为什么?
编辑:我喜欢 IOmniTaskCOntrol.Unobserved
类上的 ITask
接口,因为它允许松散耦合和代码注入。 (上一篇:因为 TThread 可能会被弃用:别提了)
问题
我想知道是否(以及如何!)使用 TThread
和 TTask.Create(aProc:TProc)
接口可以实现相同的效果。到目前为止,分析源代码对我没有帮助。
解决方法
答案很简单:您无需做任何特别的事情。 ITask
调用返回的 TTask.Create
接口也在内部由 InternalExecute
方法“保留”,因此底层 TTask
对象将通过引用计数销毁。如果“主”线程不持有 ITask 接口,子线程将。直到它终止。
因此以这种方式使用 TTask
非常简单。
注意:在 RS10.4.2 中这是有效的,我怀疑使用捕获的接口变量可能会在 10.4.1 及更早版本中导致问题,因为内联 var 问题与匿名过程相结合。 (没试过)