Niyoko
Niyoko

Reputation: 7662

How to free a thread in delphi

I have multithreaded application as I ask here. I want to terminate the thread, and start a new one when following method is called.

procedure TFRABData.RefreshDataset;
var
  GridUpdater: TGridUpdater;
begin
  if Assigned(updaterThread) and (updaterThread <> nil) then
  begin
    updaterThread.Terminate;
  end;
  GridUpdater := TGridUpdater.Create(True);
  GridUpdater.OwnerForm := Self;
  updaterThread := GridUpdater;
  GridUpdater.FreeOnTerminate := False;
  GridUpdater.Start;
  CodeSite.Send('RefreshDataset executed');
end

but, when FreeOnTerminate set to True, I get Access Violation, but when FreeOnTerminate set to False, I get memory leak. How to free the thread?

Upvotes: 6

Views: 17141

Answers (3)

Remy Lebeau
Remy Lebeau

Reputation: 595710

You need to call Terminate(), WaitFor() and Free() all together, eg:

procedure TFRABData.RefreshDataset; 
var 
  GridUpdater: TGridUpdater; 
begin 
  if Assigned(updaterThread) then 
  begin 
    updaterThread.Terminate; 
    updaterThread.WaitFor; 
    FreeAndNil(updaterThread); 
  end; 
  GridUpdater := TGridUpdater.Create(True); 
  GridUpdater.OwnerForm := Self; 
  GridUpdater.Start; 
  updaterThread := GridUpdater; 
  CodeSite.Send('RefreshDataset executed'); 
end;

Upvotes: 11

NGLN
NGLN

Reputation: 43649

And in addition to RRUZ's answer, to let it work with FreeOnTerminate = False:

Terminate just sets the flag, it does nothing more.

Change

  if Assigned(updaterThread) and (updaterThread <> nil) then 
  begin 
    updaterThread.Terminate; 
  end; 

to

  if Assigned(updaterThread) then 
  begin 
    updaterThread.Free; 
  end; 

Free will call Terminate and WaitFor subsequently to eliminate your memory leak.

Upvotes: 8

RRUZ
RRUZ

Reputation: 136391

  1. avoid the need of start a suspended thread
  2. modify your TThread constructor to receive the OwnerForm parameter
  3. set the FreeOnTerminate value in the constructor of your thread.
  4. Start the TThread in a not suspended state.

something like so.

  TGridUpdater = class(TThread)
  private
    FOwnerForm: TForm;
  public
    constructor Create(OwnerForm : TForm); overload;
    destructor Destroy; override;
    procedure Execute; override;
  end;

constructor TGridUpdater.Create(OwnerForm: TForm);
begin
  inherited Create(False);
  FreeOnTerminate := True;
  FOwnerForm:=OwnerForm;
end;

destructor TGridUpdater.Destroy;
begin

  inherited;
end;

procedure TGridUpdater.Execute;
begin
  //your code goes here

end;

Now you can create your Tthread on this way

GridUpdater:=TGridUpdater.Create(Self); //Just set it and forget it

Upvotes: 6

Related Questions