Recent

Author Topic: I'm NOT Able to Stop This Thread....  (Read 647 times)

AaronCatolico1

  • New Member
  • *
  • Posts: 22
I'm NOT Able to Stop This Thread....
« on: November 03, 2024, 02:44:57 am »
I have a button1 and a label1. When the button1 is clicked, the label1 starts counting up on it's own thread.

The issue is that I have NOT been able to stop the thread when button2 is clicked.

Here's the code I'm working with:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6.   System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  7.   FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  8.   FMX.Controls.Presentation, FMX.StdCtrls, System.SyncObjs;
  9.  
  10. type
  11.   TForm1 = class(TForm)
  12.     Button1: TButton;
  13.     Label1: TLabel;
  14.     Button2: TButton;
  15.     procedure Button1Click(Sender: TObject);
  16.     procedure Button2Click(Sender: TObject);
  17.   private
  18.  
  19.   public
  20.  
  21.   end;
  22.  
  23.  
  24.  
  25. { TMyThread is the class that will handle background work for Label1 }
  26. MyThread1 = class(TThread)
  27. private
  28.     count: Integer;
  29.     msg: string;
  30.      stopThread:boolean;
  31. protected
  32.     procedure Execute; override;
  33.     procedure UpdateUI;
  34. public
  35.     constructor Create;
  36. end;
  37.  
  38.  
  39.  
  40.  
  41.  
  42. var
  43.   Form1: TForm1;
  44.  
  45. implementation
  46.  
  47. {$R *.fmx}
  48.  
  49.  
  50.  
  51.  
  52. { MyThread Constructor }
  53. constructor MyThread1.Create;
  54. begin
  55.   inherited Create(False); // False means it will start right away
  56.   FreeOnTerminate := True; // Free memory when finished
  57. end;
  58.  
  59.  
  60.  
  61.  
  62. { Worker Thread for Label1 }
  63. procedure MyThread1.Execute;
  64. var
  65.   i: Integer;
  66. begin
  67.   for i := 1 to 1000 do
  68.   begin
  69.  
  70.   //Check to see if the was terminated. If so, then exit the for loop.
  71.     if Terminated then
  72.         Exit;
  73.  
  74.     Sleep(10); // Simulate work (1 second per iteration)
  75.     msg := '# ' + IntToStr(i);
  76.     Synchronize(UpdateUI); // Update UI safely from the main thread
  77.   end;
  78.  
  79.   Synchronize(UpdateUI);
  80. end;
  81.  
  82.  
  83.  
  84. { Update the UI for Label1 }
  85. procedure MyThread1.UpdateUI;
  86. begin
  87.   Inc(count);
  88.   Form1.Label1.Text := msg;
  89.  
  90.   //WHen finished:
  91.   if (count = 1000) then
  92.   begin
  93.      ShowMessage('Thread 1 Finished!');
  94.   end;
  95.  
  96. end;
  97.  
  98.  
  99.  
  100.  
  101. {Start the thread when button1 is clicked}
  102. procedure TForm1.Button1Click(Sender: TObject);
  103.  
  104. begin
  105.  
  106.   MyThread1.Create; // Create and start the first thread for Label1
  107.  
  108. end;
  109.  
  110.  
  111.  
  112. procedure TForm1.Button2Click(Sender: TObject);
  113.     //Procedure to stop the MyThread1 thread goes here.
  114.  
  115. begin
  116.  
  117. end;
  118.  
  119. end.


Fibonacci

  • Hero Member
  • *****
  • Posts: 594
  • Internal Error Hunter
Re: I'm NOT Able to Stop This Thread....
« Reply #1 on: November 03, 2024, 02:53:45 am »
You dont have any "handle" to the thread you created, thus you cant do anything with it. Simply assign it to a variable, then you can call Terminate on the thread object.

Create global var of type MyThread1

Code: Pascal  [Select][+][-]
  1. var
  2.   mt: MyThread1;

In button 1 create your thread

Code: Pascal  [Select][+][-]
  1. mt := MyThread1.Create;

In button 2 terminate your thread

Code: Pascal  [Select][+][-]
  1. mt.Terminate;

AaronCatolico1

  • New Member
  • *
  • Posts: 22
Re: I'm NOT Able to Stop This Thread....
« Reply #2 on: November 03, 2024, 03:06:34 am »
Can you show me how to create the global variable?
I'm new to using Pascal, so not sure exactly how it's declared yet.


You dont have any "handle" to the thread you created, thus you cant do anything with it. Simply assign it to a variable, then you can call Terminate on the thread object.

Create global var of type MyThread1

Code: Pascal  [Select][+][-]
  1. var
  2.   mt: MyThread1;

In button 1 create your thread

Code: Pascal  [Select][+][-]
  1. mt := MyThread1.Create;

In button 2 terminate your thread

Code: Pascal  [Select][+][-]
  1. mt.Terminate;

Fibonacci

  • Hero Member
  • *****
  • Posts: 594
  • Internal Error Hunter
Re: I'm NOT Able to Stop This Thread....
« Reply #3 on: November 03, 2024, 03:09:22 am »
You can place this line

Code: Pascal  [Select][+][-]
  1. mt: MyThread1;

Right here

Code: Pascal  [Select][+][-]
  1. var
  2.   Form1: TForm1;
  3.   mt: MyThread1;

AaronCatolico1

  • New Member
  • *
  • Posts: 22
Re: I'm NOT Able to Stop This Thread....
« Reply #4 on: November 03, 2024, 03:15:28 am »
Awesome! It worked! Thank you! Also, what's the best way to pause the thread in this case? What would you recommend?



You can place this line

Code: Pascal  [Select][+][-]
  1. mt: MyThread1;

Right here

Code: Pascal  [Select][+][-]
  1. var
  2.   Form1: TForm1;
  3.   mt: MyThread1;

Fibonacci

  • Hero Member
  • *****
  • Posts: 594
  • Internal Error Hunter
Re: I'm NOT Able to Stop This Thread....
« Reply #5 on: November 03, 2024, 03:30:25 am »
Awesome! It worked! Thank you! Also, what's the best way to pause the thread in this case? What would you recommend?

You can suspend (mt.Suspend) the thread and then resume (mt.Resume), but that can have side effects.

Safe way would be to create a variable, say named "isPaused", then in button 2 you set it to true "mt.isPaused := true", then in your thread loop check if isPaused is true and if it is then just do nothing or do some Sleep(). Create another button which will set mt.isPaused to false.

Lecture for you: https://wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial

Code: Pascal  [Select][+][-]
  1. MyThread1 = class(TThread)
  2. private
  3.   count: integer;
  4.   msg: string;
  5.   stopThread: boolean;
  6. protected
  7.   procedure Execute; override;
  8.   procedure UpdateUI;
  9. public
  10.   constructor Create;
  11.   isPaused: boolean;
  12. end;

Code: Pascal  [Select][+][-]
  1. { Worker Thread for Label1 }
  2. procedure MyThread1.Execute;
  3. var
  4.   i: integer;
  5. begin
  6.   for i := 1 to 1000 do begin
  7.     // Check to see if the was terminated. If so, then exit the for loop.
  8.     if Terminated then Exit;
  9.     while isPaused do sleep(1);
  10.  
  11.     Sleep(10); // Simulate work (1 second per iteration)
  12.     msg := '# ' + IntToStr(i);
  13.     Synchronize(UpdateUI); // Update UI safely from the main thread
  14.   end;
  15.  
  16.   Synchronize(UpdateUI);
  17. end;

It can be improved to allow termination while paused:

Code: Pascal  [Select][+][-]
  1. procedure MyThread1.Execute;
  2. var
  3.   i: integer;
  4. begin
  5.   for i := 1 to 1000 do begin
  6.     while isPaused and not Terminated do sleep(1);
  7.     // Check to see if the was terminated. If so, then exit the for loop.
  8.     if Terminated then Exit;
  9.  
  10.     Sleep(10); // Simulate work (1 second per iteration)
  11.     msg := '# ' + IntToStr(i);
  12.     Synchronize(UpdateUI); // Update UI safely from the main thread
  13.   end;
  14.  
  15.   Synchronize(UpdateUI);
  16. end;
« Last Edit: November 03, 2024, 03:33:18 am by Fibonacci »

Fred vS

  • Hero Member
  • *****
  • Posts: 3410
    • StrumPract is the musicians best friend
Re: I'm NOT Able to Stop This Thread....
« Reply #6 on: November 03, 2024, 04:47:21 am »
what's the best way to pause the thread in this case? What would you recommend?

For pausing thread, you may use a RTLevent:

Code: Pascal  [Select][+][-]
  1. var
  2.       Form1: TForm1;
  3.       mt: MyThread1;
  4.       evPause: PRTLEvent;  // For pausing

In button 1 create your thread:
Code: Pascal  [Select][+][-]
  1. mt := MyThread1.Create;
  2. evPause := RTLEventCreate; // create the event
  3. RTLeventSetEvent(evPause); // To initialize the event

In new button "Pause":
Code: Pascal  [Select][+][-]
  1. RTLeventResetEvent(evPause); // To pause the thread

In new button "Resume":
Code: Pascal  [Select][+][-]
  1. RTLeventSetEvent(evPause); // To Re-initialize the event

In button 2 terminate your thread;
Code: Pascal  [Select][+][-]
  1. RTLeventdestroy(evPause); // Free the event
  2. mt.Terminate;

And in the loop of MyThread1.Execute add:
Code: Pascal  [Select][+][-]
  1.       RTLeventWaitFor (evPause);    // is there a pause waiting ?
  2.       RTLeventSetEvent (evPause);
« Last Edit: November 03, 2024, 05:39:57 am by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Thaddy

  • Hero Member
  • *****
  • Posts: 16138
  • Censorship about opinions does not belong here.
Re: I'm NOT Able to Stop This Thread....
« Reply #7 on: November 03, 2024, 07:32:54 am »
Since when are we supporting Delphi? FMX? FMX is prone to threading problems and does not even work on fpc/lazarus.
Ask on a Delphi forum.
A couple of  things to correct the above:
1. If the thread does not listen to the event, it won't stop.
2. Terminate is a request model, it won't stop the thread if it does not listen, it is similar to 1.
3. you can kill a thread permanently the dirty way through its handle.
and
4. FMX, depending on Delphi version is more likely the cause. itself. As opposed to LCL/VCL a lot of threading is going on in the background in FMX and for a proper answer you should ask on a forum with users that are more familiar with fmx than the average Lazarus user. (Although there are some)
« Last Edit: November 03, 2024, 07:44:22 am by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

Warfley

  • Hero Member
  • *****
  • Posts: 1734
Re: I'm NOT Able to Stop This Thread....
« Reply #8 on: November 03, 2024, 02:19:45 pm »
On a side note, if you access the thread variable from the main thread, freeonterminate is very dangerous. Either reset that variable in the on-terminate event, or manually free the thread

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1427
    • Lebeau Software
Re: I'm NOT Able to Stop This Thread....
« Reply #9 on: November 03, 2024, 05:42:15 pm »
Since when are we supporting Delphi? FMX? FMX is prone to threading problems and does not even work on fpc/lazarus.
Ask on a Delphi forum.

They already did, actually:
https://en.delphipraxis.net/topic/12480-im-not-able-to-stop-this-thread/
https://stackoverflow.com/questions/79151889/how-to-stop-a-thread-in-delphi
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

 

TinyPortal © 2005-2018