How to close anonymous threads in Delphi when closing an application?

I have a Delphi application that spawns 6 anonymous threads on some TTimer.OnTimer events.

If I close the application using the X button in the title bar, the Access Violation at the address $ C0000005 will be raised, and FastMM will report the TAnonymousThread objects that have been leaked.

What is the best way to free anonymous thread in Delphi created in the OnTimer event using the TThread.CreateAnonymousThread () method?

SOLUTION that worked for me:

Created a shell of anonymous threads that terminates them, being free.

type TAnonumousThreadPool = class sealed(TObject) strict private FThreadList: TThreadList; procedure TerminateRunningThreads; procedure AnonumousThreadTerminate(Sender: TObject); public destructor Destroy; override; final; procedure Start(const Procs: array of TProc); end; { TAnonumousThreadPool } procedure TAnonumousThreadPool.Start(const Procs: array of TProc); var T: TThread; n: Integer; begin TerminateRunningThreads; FThreadList := TThreadList.Create; FThreadList.Duplicates := TDuplicates.dupError; for n := Low(Procs) to High(Procs) do begin T := TThread.CreateAnonymousThread(Procs[n]); TThread.NameThreadForDebugging(AnsiString('Test thread N:' + IntToStr(n) + ' TID:'), T.ThreadID); T.OnTerminate := AnonumousThreadTerminate; T.FreeOnTerminate := true; FThreadList.LockList; try FThreadList.Add(T); finally FThreadList.UnlockList; end; T.Start; end; end; procedure TAnonumousThreadPool.AnonumousThreadTerminate(Sender: TObject); begin FThreadList.LockList; try FThreadList.Remove((Sender as TThread)); finally FThreadList.UnlockList; end; end; procedure TAnonumousThreadPool.TerminateRunningThreads; var L: TList; T: TThread; begin if not Assigned(FThreadList) then Exit; L := FThreadList.LockList; try while L.Count > 0 do begin T := TThread(L[0]); T.OnTerminate := nil; L.Remove(L[0]); T.FreeOnTerminate := False; T.Terminate; T.Free; end; finally FThreadList.UnlockList; end; FThreadList.Free; end; destructor TAnonumousThreadPool.Destroy; begin TerminateRunningThreads; inherited; end; 

The end is here, as you can call it:

 procedure TForm1.Button1Click(Sender: TObject); begin FAnonymousThreadPool.Start([ // array of procedures to execute procedure{anonymous1}() var Http: THttpClient; begin Http := THttpClient.Create; try Http.CancelledCallback := function: Boolean begin Result := TThread.CurrentThread.CheckTerminated; end; Http.GetFile('http://mtgstudio.com/Screenshots/shot1.png', 'c:\1.jpg'); finally Http.Free; end; end, procedure{anonymous2}() var Http: THttpClient; begin Http := THttpClient.Create; try Http.CancelledCallback := function: Boolean begin Result := TThread.CurrentThread.CheckTerminated; end; Http.GetFile('http://mtgstudio.com/Screenshots/shot2.png', 'c:\2.jpg'); finally Http.Free; end; end ]); end; 

No memory leak, proper shutdown and easy to use.

+8
source share
3 answers

If you want to maintain and control the lifetime of a thread, then it must have FreeOnTerminate set to False . Otherwise, it is an error to refer to the stream after it starts. This is because as soon as it starts to run, you have no ready-made way to find out if it is released.

A call to CreateAnonymousThread creates a thread with FreeOnTerminate set to True .

The stream is also marked as FreeOnTerminate, so you should not touch the returned instance after calling Start.

And so, but by default you cannot control the lifetime of the thread. However, you can set FreeOnTerminate to False just before calling Start . Like this:

 MyThread := TThread.CreateAnonymousThread(MyProc); MyThread.FreeOnTerminate := False; MyThread.Start; 

However, I'm not sure I will do it. The design of CreateAnonymousThread is that the thread is automatically freed upon completion. I think that personally I will either follow the intended design or get my own TThread descendant.

+15
source

To avoid errors with CreateAnonymousThread , just set FreeOnTerminate to False before running it.

Thus, you can work with the stream, as usual, without any workarounds.

You can read the documentation that says CreateAnonymousThread automatically sets FreeOnTerminate to True , and that is what causes the errors when accessing the thread.

+9
source

Make your streams to view some kind of notification from the outside. It can be an event that receives a signal, a message sent to a window belonging to a stream, a command sent through a socket that listens to your stream, or any other form of communication that you find.

If you determine that this problem is related to the fact that your threads are so-called โ€œanonymousโ€ threads, then it will be easier for you to make them non-anonymous. Put the body of the anonymous function in the Execute method and pass any captured variables to the thread class through its constructor.

+3
source

All Articles