Reputation: 389
Get leakage report (Tsrch_slave_thread, TSimpleEvent) after closing the app. I understand the app quits before the thread can free itself, but how to avoid? How to wait for the thread to finish?
Thank You.
Definition of the worker thread >>
- FreeOnTerminate is set to true
- OnTerminate : TMaster.slvsrch_termination();
Tsrch_slave_thread = class(TThread)
private
FSW: TStopWatch;
protected
procedure Execute; override;
public
SimpleEvent: TSimpleEvent;
master: TMaster;
master_HWND: HWND;
procedure DoTerminate; override;
constructor Create;
destructor Destroy; override;
end;
procedure Tsrch_slave_thread.Execute;
var
text_orig: string;
activesearch: integer;
begin
FSW.Start;
while not terminated do begin
activesearch := master.CMD_LISTCNT;
//stopper refresh
synchronize(procedure begin
with self.master do
Fmasternode.text := FmasterDat.MstrName + ' (' + floattostr(Fsw.ElapsedMilliseconds / 1000) + 'sec - Searching)';
end);
if (SimpleEvent.WaitFor(2000) <> wrTimeOut) or (activesearch <> 1) then break;
end;
FSW.Stop;
end;
TMaster (holding the reference for the worker thread) >>
TMaster = class(TObject)
private
...
Fslave_search_thread : Tsrch_slave_thread;
...
public
...
end;
Destructor of TMaster (i set the worker thread's terminate flag from here) >>
destructor TMaster.Destroy;
begin
FSlaveList.free;
DeallocateHWnd( fMsgHandlerHWND );
if assigned( self.Fslave_search_thread ) then self.Fslave_search_thread.terminate;
inherited;
end;
Freeing TMaster instances in the main form's OnClose event handler >>
procedure TfrmCLmain.FormClose(Sender: TObject; var Action: TCloseAction);
...
node := frmDevTree.JvTreeView1.Items.GetFirstNode;
if node.data <> nil then
begin
while Assigned(Node) do begin
if TObject(node.data) is TMaster then
TMaster(node.data).free;
node := node.getNextSibling;
end;
end;
...
freeandnil(udpsend);
action := caFree;
end;
Destructor of Tsrch_slave_thread >>
destructor Tsrch_slave_thread.destroy;
begin
self.SimpleEvent.free;
inherited;
end;
Tsrch_slave_thread.DoTerminate >>
procedure Tsrch_slave_thread.DoTerminate;
begin
inherited;
self.master.FlastSearchTime := self.FSW.ElapsedMilliseconds / 1000;
self.simpleEvent.SetEvent;
end;
Tsrch_slave_thread's OnTerminate event handler >>
procedure TMaster.slvsrch_termination(Sender: TObject);
begin
if Assigned(Fslave_search_thread) then
begin
self.FLastSearchTime := Fslave_search_thread.FSW.ElapsedMilliseconds - SEARCH_DELAY_SEC;
Fslave_search_thread := nil;
end;
...
postmessage ( self.FMasterDevFrmHND, WM_SLVSRCH_COMPLETE, integer(self), 0);
end;
Upvotes: 1
Views: 144
Reputation: 612874
Simply put you need to destroy the thread as well as terminate it. Add a call to Free
immediately after you terminate the thread.
destructor TMaster.Destroy;
begin
FSlaveList.free;
DeallocateHWnd(fMsgHandlerHWND);
if assigned(Fslave_search_thread) then
Fslave_search_thread.terminate;
Fslave_search_thread.Free;
inherited;
end;
As an aside, excessive use of Self
will make the code harder to read.
Upvotes: 1