TThread.CreateAnonymousthread / FreeOnTerminate 但随后使用 TTask / ITask
Posted
技术标签:
【中文标题】TThread.CreateAnonymousthread / FreeOnTerminate 但随后使用 TTask / ITask【英文标题】:TThread.CreateAnonymousthread / FreeOnTerminate but then with TTask / ITask 【发布时间】:2021-05-31 00:13:45 【问题描述】:背景
使用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
-> Destroy
被调用),该接口将被释放,导致线程来生成一个 AV。
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
接口可以完成相同的操作。到目前为止,分析源代码对我没有帮助。
【问题讨论】:
不,TThread
不会被弃用。
这个问题请求minimal reproducible example,包括您使用的是哪个 Delphi 版本 - 但我只知道这一点,因为我知道在 10.4 和 10.4.1 中捕获内联变量存在问题。但是从你问题中的代码来看,你没有捕获任何东西,所以真的不清楚你的问题到底是什么。
TThread 不会被弃用,因为 TTask 实际上在下面使用 TThread。
我喜欢 ITask 接口(松耦合/代码注入原理),这主要是为什么我更喜欢 ITask 解决方案而不是 TThread 解决方案。忘记关于 TThread 被弃用的评论吧,这不是重点。
【参考方案1】:
答案很简单:你不必做任何特别的事情。 TTask.Create
调用返回的ITask
接口也被InternalExecute
方法在内部“保留”,因此底层TTask
对象将通过引用计数被销毁。如果“主”线程不持有 ITask 接口,子线程将。直到它终止。
所以以这种方式使用TTask
非常简单。
注意:在 RS10.4.2 中这可行,我怀疑使用捕获的接口变量可能会在 10.4.1 和更早版本中导致问题,因为内联 var 问题与匿名 procs 相结合。 (没试过)
【讨论】:
只要去掉内联变量就可以了。如果出于某种原因需要变量,请将其移至过程 var 块。 是的,看来我还有其他问题。即使我删除了 lTask:=nil 语句,我似乎也无法以某种方式重新创建我的 AV。我显然必须重新调查。我还发现了 TTask.CurrentTask,它实际上包含当前线程的 ITask。酷。以上是关于TThread.CreateAnonymousthread / FreeOnTerminate 但随后使用 TTask / ITask的主要内容,如果未能解决你的问题,请参考以下文章