Delphi TThread handle error

Multi tool use
Multi tool use


Delphi TThread handle error



I am reading "Delphi High performance" and there is something that I am missing. Given this code as test:


type TTest = class(TThread)
private
amemo: TMemo;
public
constructor Create(ss: boolean; memo: TMemo);
protected
procedure Execute; override;
end;

constructor TTest.Create(ss: boolean; memo: TMemo);
begin
inherited Create(ss);
FreeOnTerminate := true;
amemo := memo;
end;

procedure TTest.Execute;
var i: uint32;
begin
inherited;
i := 0;

while not Terminated do
begin
Inc(i);
Synchronize(procedure
begin amemo.Lines.Add(i.ToString) end);
Sleep(1000);
end;

end;



Very simply, this thread prints some numbers in a memo. I start the thread suspended and so I have to call this piece of code:


procedure TForm1.Button1Click(Sender: TObject);
begin
thread := TTest.Create(true, Memo1);
thread.Start;
end;



I have always stopped the thread calling thread.Terminate; but reading the book I see that Primoz stops a thread like this:


thread.Terminate;


procedure TForm1.Button2Click(Sender: TObject);
begin
thread.Terminate;
thread.WaitFor; //he adds this method call
//FreeAndNil(thread)
//there is the above line as well in the code copied from the book but I have removed it since I have set FreeOnTerminate := true (so I dont have to worry about freeing the obj).
end;



At this point, if I run the code using only Terminate I have no problems. If I run the code with Terminate + WaitFor I get this error:


Terminate



enter image description here



I have read more coding in delphi too and I see that Nick Hodges just makes a call to Terminate;. Is calling Terminate; enough to safey stop a thread? Note that I've set FreeOnTerminate := true so I don't care about the death of the object. Terminated should stop the execution (what is inside execute) and so it should be like this:


Terminate;


Terminate;


FreeOnTerminate := true



Please tell me what I'm missing.



Note.
In the book the thread doesn't have FreeOnTerminate := true. So the thread needs to be freed manually; I guess that this is the reason why he calls


FreeOnTerminate := true


thread.Terminate;
thread.WaitFor;
FreeAndNil(thread)



I agree on Terminate (stop the thread= and FreeAndNil (free the object manually) but the WaitFor?





Once you start a thread with FreeOnTerminate true then you must not use a reference to the thread again because you can't guarantee that it is valid.
– David Heffernan
Jun 30 at 17:03





@DavidHeffernan I think I've got it. When I call thread.Terminate; the thread dies and then, since FreeOnTerminate is true, the object is freed. Since the the object is free calling WaitFor won't work of course. (which is what you're saying)
– Raffaele Rossi
Jun 30 at 17:09






On a side note, you're not supposed to call inherited from within Execute.
– Jerry Dodge
Jun 30 at 18:01


inherited


Execute





@ruff The thread might terminate before you call terminate. If you must keep a reference you need to nil it in On Terminate.
– David Heffernan
Jun 30 at 21:09





WaitFor() should not be used with FreeOnTerminate=True, because the thread handle is closed when the thread object is freed, which is what causes the "handle is invalid" exception. FreeOnTerminate=True should only be used for "start-and-forget" type of threads.
– Remy Lebeau
Jun 30 at 21:19




1 Answer
1



Please tell me what I'm missing.



The documentation for FreeOnTerminate explicitly says that you cannot use the Thread in any way after Terminate.


FreeOnTerminate


Terminate



That includes your WaitFor call, which would work on a possibly already free'd object. This use-after-free can trigger the error above, among other even more "interesting" behaviours.


WaitFor





The documentation is too lenient. You can't really access a FreeOnTerminate=True thread for any reason. The thread might terminate itself (crash, etc) before you have even had a chance to call Terminate at all. You should use FreeOnTerminate=True only for "start-and-forget" threads that you don't care about accessing after starting them. But once you need to access them for any reason, FreeOnTerminate=True becomes dangerous to use
– Remy Lebeau
Jul 1 at 20:58


FreeOnTerminate=True


Terminate


FreeOnTerminate=True


FreeOnTerminate=True






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

fj,gMVEy3awy275I,tsymDihwJJtD GId6Xn08lgavu0FYWqOL5bXI,gZ1lQ4i7LbQy
br kSSy,b54TDs gW X7jxriS,NzCFbUJ1,V,Ku V7ttZhbc2H

Popular posts from this blog

PySpark - SparkContext: Error initializing SparkContext File does not exist

django NoReverseMatch Exception

List of Kim Possible characters