You can't set FreeOnTerminate
to True
and call Free
on the thread instance. You have to do one or the other, but not both. As it stands your code destroys the thread twice. You must never destroy an object twice and of course when the destructor runs for the second time, errors occur.
What happens here is that since you created the thread suspended, nothing happens until you explicitly free the thread. When you do that the destructor resumes the thread, waits for it to complete. This then results in Free
being called again because you set FreeOnTerminate
to True
. This second call to Free
closes the handle. Then you return to the thread proc and that calls ExitThread
. This fails because the thread's handle has been closed.
As Martin points out in the comment you must not create TThread
directly since the TThread.Execute
method is abstract. Also, you should not use Resume
which is deprecated. Use Start
to begin execution of a suspended thread.
Personally I don't like to use FreeOnTerminate
. Using this feature results in the thread being destroyed on a different thread from which it was created. You typically use it when you want to forget about the instance reference. That then leaves you uncertain as to whether or not the thread has been destroyed when your process terminates, or even whether it is terminating and freeing itself during process termination.
If you must use FreeOnTerminate
then you need to make sure that you don't call Free
after having set FreeOnTerminate
to True
. So the obvious solution is to set FreeOnTerminate
to True
immediately before after calling Start
and then forget about the thread instance. If you have any exceptions before you are ready to start then you can safely free the thread then since you FreeOnTerminate
would still be False
at that point.
Thread := TMyThread.Create(True);
Try
//initialise thread object
Except
Thread.Free;
raise;
End;
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;
A more elegant approach would be to move all the initialisation into the TMyThread
constructor. Then the code would look like this:
Thread := TMyThread.Create(True);
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;
FreeOnTerminate
until just before you callResume
. – CindycineTerminate
,Resume
and thenWaitFor
. – RelativizeThread.Resume
is indeed called. It happens when you callAThread.Free
. – RelativizeFreeOnTerminate
can be set in yourTThread.Create
constructor. – Highminded