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的主要内容,如果未能解决你的问题,请参考以下文章