ABort a Task by GUI Button lazarus / 64-FPC development ---------------------------------------------------------------------- ArminLinder · 2019-02-06 12:31 Hi all, please forgive me if I ask a question which could have been asked before, where the answer may be somewhere on page xxx of some doc, or which I could probably have solved myself. I am right now not allowed to spend time using FPC by order from above, seems there isn't much trust there when a product doesn't cost $$$$$ and is backed by some well known company name. I just ran into a wicked problem using some other so-called technology (web ... Javascript), using a framework from one of those well known companies, wasted a lot of time and still haven't found a satisfying solution, and wonder whether there would be a better solution in Lazarus/FPC. The problem is, in a event driven program, to abort a long running task from the GUI. The only option I have right now (in the programming environment I am forced to use) is that I can set a global flag variable, and spread queries all over the long running task code. As soon as the code hits into one of those many queries, I can try to abort the task code. There are two problems with this: if the long running task spends time in a sleep state, it won't abort until the current sleep has reached its limit, given I put queries to my variable right after every sleep. The second problem ist that the environment I currently am forced use doesn't fire a separate task when one hits a button, but queues the button press message in some main task event loop, where it resides until the long-running task has returned. Pressing some abort button thus doesn't have any effect, since it's handling routine won't be called until the long running task returns, and so the mnagic variable cannot be set before the task has finished anyway. Simple question: does Lazarus/FPC better, and if yes, where can I read more about it? Thx, Armin. ---------------------------------------------------------------------- balazsszekely · 2019-02-06 12:39 Run the long taks in a worker thread. ---------------------------------------------------------------------- Bart · 2019-02-06 12:43 The task can have a callback function, and that function can indicate wether to abort the task. The callback function will be a method of the main thread. Bart ---------------------------------------------------------------------- ArminLinder · 2019-02-06 15:22 Thank you for your responses. Your leads brought me here ... http://wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial# Do_you_need_multi-threading.3F The "Terminated" flag seems to be the suggested solution. Hm, doesn't this look like the clumsy "check variable as often as you can" approach? Armin. P.S. What I am after is something like this (don't care about syntax ...) var MyTask : Task = NIL ... MyTask = new Task MyTask.Body = ( .... the long running code thing as a closure, or a reference to a function, or inserrted via inheritance and extension of a "Body" member, whatever the language suipports  ....) ... # if it's time for the task to be fired up myTask.Run() # and the GUI button handler like this: MyButton.OnClick()     {     if MyTask <> NIL Then MyTask.Kill()     # Kill the thing immedately, no questions asked, probably also Kill(MyTask)     } ---------------------------------------------------------------------- marcov · 2019-02-06 22:08 Basically there are two options: - poll variables. - block on signals (using waitforsingle/multiple or TEvents). IOW semaphores. Using events allows you to sleep longer and yet be quite responsive, since you can short-circuit the pauze. ---------------------------------------------------------------------- ArminLinder · 2019-02-07 10:41 Marcov, thanks for your hints. Quote from: marcov on February 06, 2019, 11:08:09 pm - block on signals (using waitforsingle/multiple or TEvents). IOW semaphores. Can you guide me to a sample/tutorial showing this approach? I am really curious how the "abort code somewhere in the middle" problem is solved using it. Btw, I still wonder why the approach I have sketched above isn't implemented in FPC, is it? It seems like the most logical approach to me, but FPC seems not to work like that, there must be reasons, I wonder what they are. Do you happen to know? Thanks, Armin. ---------------------------------------------------------------------- engkin · 2019-02-07 19:35 If you are brave enough, kill the thread using: KillThread from the RTL or TerminateThread from Windows. But make sure you understand and don't mind the consequences of calling TerminateThread. Another possibility is to do a calculated exit using the code provided in this thread. Here you can control how to leave the long task, and have a change to free the memory and notify the main thread, if needed. If you don't understand it, then most likely you don't need any of this. ---------------------------------------------------------------------- ArminLinder · 2019-02-08 11:03 Quote from: engkin on February 07, 2019, 08:35:35 pmKillThread from the RTL or TerminateThread from Windows. But make sure you understand and don't mind the consequences of calling TerminateThread. Ah, there is the shotgun aproach I was after :-) I'd expect problems with memory management, especially heap corruption problems when allocating objects dynamically, and probably some similar problems with allocated resources, like open file handles. As long as the thread code isn't very complex it seems possible to deal with - if the thread code requires any of those at all. Am I seeing things too simple? If I KillThread a Thread, doesn't the Thread object destructor get called, where I could do any required cleanup work easily? Quote from: engkin on February 07, 2019, 08:35:35 pmAnother possibility is to do a calculated exit using the code provided in this thread. Here you can control how to leave the long task, and have a change to free the memory and notify the main thread, if needed. I am interested ... but the thread you've linked is a 4 page thing, and a sketchy browse over the posts didn't reveal anything which would help me with my specific problem. As far as I see they discuss several differrent topics related to the usage of GOTO. Can you please point my nose to a specific post where I can find the code you wanted me to look at? Thnx! Armin. BTW: don't we all at some point start as non-knowing toddlers, and learn? ---------------------------------------------------------------------- engkin · 2019-02-09 04:00 Quote from: Nimral on February 08, 2019, 12:03:22 pmIf I KillThread a Thread, doesn't the Thread object destructor get called, where I could do any required cleanup work easily? No, KillThread is just cross-platform function. On Windows it calls TerminateThread or whatever function assigned to the thread manager. Quote from: Nimral on February 08, 2019, 12:03:22 pmthe thread you've linked is a 4 page thing, and a sketchy browse over the posts didn't reveal anything which would help me with my specific problem. As far as I see they discuss several differrent topics related to the usage of GOTO. Can you please point my nose to a specific post where I can find the code you wanted me to look at? Armin, four pages are not a lot to read. It was not about GOTO. GOTO takes a label, does not accept anything else. Here is the idea. A typical Execute looks like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TTestThread.Execute;var  i: int64;begin  while not Terminated do  begin    { Some slow task  like}    repeat      inc(i);    until (i>=$1122334455667788) or Terminated;  end;end; This could be replaced with: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TTestThread.Execute;label  lblLoop, lblExit;var  i: int64;begin  FLoopOrExitLbl := @lblLoop;  FExitLbl := @lblExit;  i := 0;  while not Terminated do  begin    lblLoop:    inc(i);    if i<$1122334455667788 then      NewGoto(FLoopOrExitLbl)    else      Goto lblExit;  end;  lblExit:end; When you want to finish this thread, you call TestThread.Die: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TTestThread.Die;begin  FLoopOrExitLbl := lblExit;end; You can find how to write NewGoto in the aforementioned thread. But as you can see, it does not help enhancing the code, nor prevents you from scattering the code with more unnecessary lines.