1

Background

Using the TThread.CreateANonymousThread(aProc:TProc) I can create a thread that destroys the thread object after the thread has terminated. (or alternatively by setting FreeOnTerminate to true for athread object). This allws the thread initiator routine th finish and go out of scope, while the tread keeps on running. (That's what I am looking for)

procedure StartProcess
begin

  var lTask:=TThread.CreateAnonymousThread(
    procedure
    begin
       ... Do lengthy thread stuff here 
    end
    );
  ...
  lTask.Start;
end;

The problem arises that TTask.Create returns an ITask interface that gets to be released when the thread initiator code drops its context (RefCount drops to 0 -> Destroy gets called), resulting in the thread to generate an 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

In case of OmniThread we have a solution called IOmniTaskCOntrol.Unobserved that avoids the task object getting destroyed before it is finished.

Why?

EDIT: I like the ITask interface over the TThread class because it allows loose coupling and code injection. (prev: Because TThread might be deprecated: just forget about that)

Question

I was wondering if (and how!) using TTask.Create(aProc:TProc) and the ITask interface the same can be accomplished. Analyzing the source code did not help me so far.

H.Hasenack
  • 1,094
  • 8
  • 27
  • 5
    No, `TThread` will not be deprecated. – Andreas Rejbrand Mar 01 '21 at 13:11
  • This question begs for [mcve], including which Delphi version you are using - but I only know that because I know there are issues with capturing inline variables in 10.4 and 10.4.1. But from code in your question you are not capturing anything so it is really not clear what exactly is your problem. – Dalija Prasnikar Mar 01 '21 at 13:43
  • 1
    TThread will not get deprecated because TTask is actually using TThread underneath. – Dalija Prasnikar Mar 01 '21 at 13:44
  • I like the ITask interface (loose coupling/code injection principle), thats mainly why I prefer the ITask solution over the TThread solution. Just forget the remark about TThread getting deprecated, it is besides the point. – H.Hasenack Mar 01 '21 at 13:46

1 Answers1

2

The answer is simple: You don't have to do anything special. The ITask interface returned by the TTask.Create call is also "held onto" internally by the InternalExecute method, so the underying TTask object will be destroyed by means of reference counting. If the "Master" thread does not hold on to the ITask interface, the subthread will. Until it has terminated.

So using TTask this way is pretty straightforward.

NOTE: In RS10.4.2 this works, I suspect using captured interface variables may cause a problem in 10.4.1 and earlier due to inline var problems combined with anonymous procs. (Didn't try)

H.Hasenack
  • 1,094
  • 8
  • 27
  • 2
    Just get rid of the inline variable and that is it. If you need variable for some reason, move it to procedure var block. – Dalija Prasnikar Mar 01 '21 at 14:07
  • Yes it seems I had something else wrong. I seem to be unable to re-create my AV somehow, even if I remove the lTask:=nil statement. I clearly have to re-investigate. I also discovered TTask.CurrentTask, which actually contains the ITask for the current thread. Cool. – H.Hasenack Mar 01 '21 at 14:18