Forum > General

TThread - How to stop a thread?

<< < (4/4)

Slawek:
Thank you for your suggestion.
I did this:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  TForm1 = class(TForm)    ...  private    ...    procedure ThreadTerminated(Sender: TObject);  public   end; procedure TForm1.btStartClick(Sender: TObject);begin  ...  MyThread := TMyThread.Create(true);  MyThread.FreeOnTerminate := True;  ...  MyThread.OnTerminate  := @ThreadTerminated;  ...  MyThread.Start;  ...end;   procedure TForm1.btStopClick(Sender: TObject);begin  MyThread.Terminate;  MyThread.WaitFor;  // MyThread := nil; //moved to ThreadTerminatedend; procedure TForm1.FormDestroy(Sender: TObject);begin  if Assigned(MyThread) then begin    MyThread.Terminate;    MyThread.WaitFor;  end;end; procedure TForm1.ThreadTerminated(Sender: TObject);begin  MyThread := nil;end; Thank you. It seems to be working properly. Does not cause errors  :)

alpine:

--- Quote from: Slawek on February 08, 2023, 09:35:35 pm ---*snip*
Thank you. It seems to be working properly. Does not cause errors  :)

--- End quote ---
You didn't change it much.

Maybe I wasn't clear enough in the previous post and I need to explain a bit more.

There is an internal procedure named TreadProc which actually is the "main" tread procedure for each TThread.  It receives a reference to the TThread instance, internally calls the the Execute method for that instance, and when that method finishes, if the FreeOnTerminate property value is true, it calls Free method. So the steps performed by TreadProc are actually (assume the name of the reference is Thread):

* If Thread still not terminated then call Thread.Execute (the thread can be terminated when initially suspended and the Terminate called prior to Start)
* Set Thread.Finished to true
* if there is a handler for Thread.OnTerminate then call it
* if Thread.FreeOnTerminate is true then call Thread.Free
* End.
Few things should be noted:

* The TThread.Terminate method just sets the Thread.Terminated property to true. That is the property the Thread.Execute must examine and exit when it becomes true (in a graceful manner)
* The Thread.Execute may finish prematurely by other means than the above Terminate mechanism, e.g. by unhandled exception. Thus, one should not expect the thread to be finished only after call to Thread.Terminate
* The above (combined with FreeOnTerminate=True) means that the reference can be freed asynchronously at any time and once started, there is no more guarantees that its reference is a valid one (not freed)
* At the other hand, the OnTerminate is called in the context of the thread itself, so there the reference is guaranteed to be valid (not yet freed)
To recap, when FreeOnTerminate=True then:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  MyThread.Terminate; isn't safe to call, actually accessing the MyThread isn't safe at all unless you catch everything (try ... except ... end) into the inner loop of MyThread.Execute

Also, when FreeOnTerminate=True and after the:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---  MyThread.Terminate; isn't safe to assume anything about the MyThread reference outside the MyThread.Execute and MyThread.OnTerminate handler body.


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm1.btStopClick(Sender: TObject);begin  MyThread.Terminate; // No more asumptions about validity of MyThread after that point  MyThread.WaitFor; // <--- Here the ThreadProc(MyThread) may already have freed the MyThread reference !!!                    //      As a pure luck, the memory contents there may still hold the old values for MyThread  // MyThread := nil; //moved to ThreadTerminatedend;
And that it doesn't cause errors now on your computer does not mean it won't make your life miserable later.

Navigation

[0] Message Index

[*] Previous page

Go to full version