Once you start self-destroying thread, you seriously limit your ability to manage it and perform required cleanup and waiting. They are convenient as fire-and-forget threads that need to run rather small tasks where task can be safely interrupted (killed) at any moment.
If the task requires cleanup, then you should not use self-destroying threads.
Besides the AV that happens during application shutdown, there are other issues with your code.
Following code is not a proper way to initialize self-destroying thread:
wtf := Twtf.Create;
wtf.FreeOnTerminate := True;
In above code thread will start running immediately after construction, and it is possible (although not very likely) that thread will complete its job, before you can set FreeOnTerminate
flag to true and that would create memory leak.
Proper way is to create thread in suspended mode, then set FreeOnTerminate
and then start a thread:
wtf := Twtf.Create(True);
wtf.FreeOnTerminate := True;
wtf.Start;
Another way to do that is overriding TThread.Create
and setting FreeOnTerminate
flag there.
Next issue is that after you start self-destroying thread, you should never ever access its reference. So you can never call wtf.Terminate
, nor call TerminateThread(wtf.Handle, 0);
because at that point thread could already been destroyed and wtf
will be dangling reference pointing to non-existing instance.
Because you cannot call wtf.Terminate
the while not Terminated
loop is also useless, unless you will be constructing other instances of that thread class which you will manually manage.
There are many ways to solve your problem, but which one you will choose depends on actual job the thread is doing and how many of such threads you need running and whether you can freely interrupt (terminate) them or you need to wait for them to finish.
If you can safely interrupt whatever thread is doing and showing AV is your only problem, then you can just wrap the code inside Execute
method with try...except
and eat up the exception.
The best option is to use manually managed thread, which you will create once and destroy when form is closing. In that case while not Terminated
loop makes sense as it will allow thread to be interrupted on application shutdown. You can also call wtf.Terminate
earlier in the application shutdown process (for instance in OnClose
, or OnCloseQuery
to give thread more time to check Terminated
flag.
procedure TForm1.Button4Click(Sender: TObject);
begin
wtf := Twtf.Create;
end;
destructor TForm1.Destroy;
begin
// calling Free will terminate thread and wait for it
wtf.Free;
inherited;
end;
Of course, there are other options for managing threads regardless of whether they are self-destroying ones or manually managed, but it is impossible to list them all, especially when your particular use case is not clear. But all those require some additional mechanisms for signaling to thread that it needs to stop its work or application that there are threads still running.
Depending on the Delphi version you are using, you might also want to look at TTask
as running and handling tasks will be easier than handling threads and threads used for running tasks are automatically managed by RTL.
If you really, really, really insist on using self-destroying threads and just want to kill everything as fast as possible once uses closes the application, then you can use TerminateProcess
. Be aware, that any abrupt termination of either threads or process by calling TerminateThread
, ExitProcess
, TerminateProcess
can cause issues if your application uses DLLs or shares memory. See: TerminateProcess function and Terminating a Process
To do that you can add following destructor in your main form:
destructor TForm1.Destroy;
begin
inherited;
TerminateProcess(GetCurrentProcess, 0);
end;
Additional reading:
How to wait that all anonymous thread are terminated before closing the app?
Can I call TerminateThread from a VCL thread?