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.
Ivelin Nikolaev
source share