In a given example I am receiving an exception when calling AThread.Free.
program Project44;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes, Windows;
type
TMyException = class(Exception);
var
AThread: TThread;
begin
AThread := TThread.Create(True);
try
AThread.FreeOnTerminate := True;
//I want to do some things here before starting the thread
//During the setup phase some exception might occur, this exception is for simulating purpouses
raise TMyException.Create('exception');
except
AThread.Free; //Another exception here
end;
end.
I have two questions:
How should I free
AThread
instance ofTThread
in a given example?I don't understand, why
TThread.Destroy
is callingResume
before destroing itself. What is the point of this?
You can't set
FreeOnTerminate
toTrue
and callFree
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 setFreeOnTerminate
toTrue
. This second call toFree
closes the handle. Then you return to the thread proc and that callsExitThread
. This fails because the thread's handle has been closed.As Martin points out in the comment you must not create
TThread
directly since theTThread.Execute
method is abstract. Also, you should not useResume
which is deprecated. UseStart
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 callFree
after having setFreeOnTerminate
toTrue
. So the obvious solution is to setFreeOnTerminate
toTrue
immediately before after callingStart
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 youFreeOnTerminate
would still beFalse
at that point.A more elegant approach would be to move all the initialisation into the
TMyThread
constructor. Then the code would look like this: