*snip*
Thank you. It seems to be working properly. Does not cause errors
You didn't change it much.
Maybe I wasn't clear enough in the previous post and I need to explain a bit more.
There is an internal procedure named
TreadProc which actually is the "main" tread procedure for each
TThread. It receives a reference to the
TThread instance, internally calls the the
Execute method for that instance, and when that method finishes, if the
FreeOnTerminate property value is true, it calls
Free method. So the steps performed by
TreadProc are actually (assume the name of the reference is
Thread):
- If Thread still not terminated then call Thread.Execute (the thread can be terminated when initially suspended and the Terminate called prior to Start)
- Set Thread.Finished to true
- if there is a handler for Thread.OnTerminate then call it
- if Thread.FreeOnTerminate is true then call Thread.Free
- End.
Few things should be noted:
- The TThread.Terminate method just sets the Thread.Terminated property to true. That is the property the Thread.Execute must examine and exit when it becomes true (in a graceful manner)
- The Thread.Execute may finish prematurely by other means than the above Terminate mechanism, e.g. by unhandled exception. Thus, one should not expect the thread to be finished only after call to Thread.Terminate
- The above (combined with FreeOnTerminate=True) means that the reference can be freed asynchronously at any time and once started, there is no more guarantees that its reference is a valid one (not freed)
- At the other hand, the OnTerminate is called in the context of the thread itself, so there the reference is guaranteed to be valid (not yet freed)
To recap, when
FreeOnTerminate=True then:
isn't safe to call, actually accessing the
MyThread isn't safe at all unless you catch everything (
try ... except ... end) into the inner loop of
MyThread.ExecuteAlso, when
FreeOnTerminate=True and after the:
isn't safe to assume anything about the
MyThread reference outside the
MyThread.Execute and
MyThread.OnTerminate handler body.
procedure TForm1.btStopClick(Sender: TObject);
begin
MyThread.Terminate; // No more asumptions about validity of MyThread after that point
MyThread.WaitFor; // <--- Here the ThreadProc(MyThread) may already have freed the MyThread reference !!!
// As a pure luck, the memory contents there may still hold the old values for MyThread
// MyThread := nil; //moved to ThreadTerminated
end;
And that it doesn't cause errors now on your computer does not mean it won't make your life miserable later.