I have a main thread and a separate thread in my program. If the separate thread finishes before the main thread, it should free itself automatically. If the main thread finishes first, it should free the separate thread.
I know about FreeOnTerminate, and I've read that you have to be careful using it.
My question is, is the following code correct?
procedure TMyThread.Execute;
begin
... Do some processing
Synchronize(ThreadFinished);
if Terminated then exit;
FreeOnTerminate := true;
end;
procedure TMyThread.ThreadFinished;
begin
MainForm.MyThreadReady := true;
end;
procedure TMainForm.Create;
begin
MyThreadReady := false;
MyThread := TMyThread.Create(false);
end;
procedure TMainForm.Close;
begin
if not MyThreadReady then
begin
MyThread.Terminate;
MyThread.WaitFor;
MyThread.Free;
end;
end;
You can simplify this to:
procedure TMyThread.Execute;
begin
// ... Do some processing
end;
procedure TMainForm.Create;
begin
MyThread := TMyThread.Create(false);
end;
procedure TMainForm.Close;
begin
if Assigned(MyThread) then
MyThread.Terminate;
MyThread.Free;
end;
Explanation:
Either use FreeOnTerminate
or free the thread manually, but never do both. The asynchronous nature of the thread execution means that you run a risk of not freeing the thread or (much worse) doing it twice. There is no risk in keeping the thread object around after it has finished the execution, and there is no risk in calling Terminate()
on a thread that has already finished either.
There is no need to synchronize access to a boolean that is only written from one thread and read from another. In the worst case you get the wrong value, but due to the asynchronous execution that is a spurious effect anyway. Synchronization is only necessary for data that can not be read or written to atomically. And if you need to synchronize, don't use Synchronize()
for it.
There is no need to have a variable similar to MyThreadReady
, as you can use WaitForSingleObject()
to interrogate the state of a thread. Pass MyThread.Handle
as the first and 0
as the second parameter to it, and check whether the result is WAIT_OBJECT_0
- if so your thread has finished execution.
BTW: Don't use the OnClose
event, use OnDestroy
instead. The former isn't necessarily called, in which case your thread would maybe continue to run and keep your process alive.