0

I am trying to override the virtual TThread::Terminate method, but am finding my override gets called only after the Terminated flag is set. What is the correct way to implement this?

TTestThrd = class(TThread)
private
    { Private declarations }

protected
    { Protected declarations }
    procedure Execute(); override;
    procedure DoTerminate(); override;

public
    { Public declarations }
end;


procedure TTestThrd.Execute();
var
    bTerminated: Boolean;
begin
    // This is the main thread loop
    try
        while (not Terminated) do
            begin
            // Sleep or use TEvent::Waitfor...
            end;
    finally
        // Terminated (or exception) so free all resources...
        bTerminated := True;        // Why is this called...
    end;
end;

procedure TTestThrd.DoTerminate();
var
    bDoTerminateCalled: Boolean;
begin
    bDoTerminateCalled := True;     // ...before this?  
    inherited;
end;
AlainD
  • 5,413
  • 6
  • 45
  • 99

2 Answers2

6

As I understand it, there is information missing from the question. It is important to read your previous question (Alternative to sleep inside a thread) and the comment trail.

You are trying to arrange that a call to Terminate signals an event that your thread is waiting on. In order for that to happen, you need to hook the call to Terminate. It's no good waiting for DoTerminate or OnTerminate because they execute after the thread procedure has finished.

In modern versions of Delphi you can override TerminatedSet. That's exactly what you need. It is fired from inside Terminate.

In older versions of Delphi, that pre-date this method, there is no way to be notified from the Terminate method. As I understand it, that is the key point. You wish to hook Terminate, and before TerminatedSet was added, no such hook existed.

If TerminatedSet is not available to you, then you will need to provide a method on your class that calls Terminate, and then performs whatever other actions you must perform. For example:

procedure TMyThread.SignalAndTerminate;
begin
  FTerminationEvent.SetEvent;
  Terminate;
end;
Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
1

The System.Classes.TThread.Terminate method has to be overridden if you want a method to be called before the Terminate property is set.
The Terminate method:

Signals the thread to terminate by setting the Terminated property to true.

From the System.Classes.TThread.DoTerminate documentation:

DoTerminate calls the OnTerminate event handler, but does not terminate the thread.

Another procedure of interest that is called before the OnTerminate event but after the Terminate property is set to True is System.Classes.TThread.TerminatedSet which is declared as abstract virtual in the TThread class.


I have no IDE with me right now but I guess that if you look in the TThread class, you'll find that the OnTerminate event handler is triggered after the Terminate property is set to True.

fantaghirocco
  • 4,761
  • 6
  • 38
  • 48
  • This looks like the answer. It appears TThread.DoTerminate is called after the TThread.Execute method has finished and it's main purpose is to call the TThread.OnTerminated event. I suspect one common use of this might be to free resources? – AlainD Nov 27 '15 at 18:40
  • Note that TThread::Terminate is not declared as virtual, so can it be overridden directly? TThread::DoTerminate is declared as virtual. – AlainD Nov 27 '15 at 18:43
  • @AlainD it should be like you say but also to handle exceptions occurred in the `Execute` method for what I can remember. Sorry, having no IDE at the moment I can't check – fantaghirocco Nov 27 '15 at 18:43
  • 3
    TerminatedSet is not abstract. Terminate cannot be overridden. – David Heffernan Nov 27 '15 at 19:03
  • oops... since this is obviously a steaming pile of crap, it shouldn't be the accepted answer. Please consider to remove the accepted flag and I'll delete the answer itself. I think there's no reason to edit my answer since the other one already states what I have failed to mean. Meanwhile I'm going to [write it out a hundred times](https://www.youtube.com/watch?v=IIAdHEwiAy8) "*TerminatedSet is not abstract. Terminate cannot be overridden.*" Thank you! :D – fantaghirocco Nov 29 '15 at 18:48