Recent

Author Topic: Assigning dynamic callBack to OnTerminate ?  (Read 914 times)

GBR

  • Newbie
  • Posts: 3
Assigning dynamic callBack to OnTerminate ?
« on: January 06, 2026, 11:45:22 pm »
Hello,
I'm stuck with quite trivial problem, but I cannot find answer anywhere.

Basically in my program I spawn TThreads dynamically. They do their jobs and then terminate. I would like to assign different callback function to each Thread.onTerminate.
But I don't know how to set that callback with dynamic arguments !

Let's explain this on example (rather pseudocode than real example):

Code: Pascal  [Select][+][-]
  1. type // this is just a helper object holding informations about jobs
  2.   TJob = object
  3.      ID: integer;
  4.      thread:TThread;
  5.      caption: string;
  6.      // (...)
  7.   end;
  8.  
  9. type TJobArray = array of TJob;
  10.  
  11. // global array
  12. var g_Jobs: TJobArray;
  13.  
  14. // Here I have this procedure which spawns new thread on button click:
  15.  
  16. procedure StartNewJob(_caption:string);
  17. var newThread: TThread;
  18. var l:integer;
  19. begin
  20.  
  21.   SpawnNewThread(newThread);
  22.  
  23.    l := Length(g_Jobs);
  24.   SetLength(g_Jobs, l + 1);
  25.  
  26.   g_Jobs[l].thread :=newThread;
  27.   g_Jobs[l].ID := l;
  28.   g_Jobs[l].caption := _caption;
  29.  
  30. { now I would like to do something like : }
  31.  
  32. newThread.OnTerminate := procedure(Sender: TObject)
  33. begin
  34.   ShowFinishingMsg(ID, caption);
  35. end;
  36. { which is an equivalent of anonymous function in JavaScript, but obviously doesn't work) }
  37.  
  38. end;
  39.  

I know in this case I could pass ID and  _caption to the Spawning function, which creates thread, but it's not the point (basically in my code each new Job also spawns new Tcontrol, and I want to modify each control at the end of each tread )
I want to assign a callback with different parameters to .onTerminate of each new thread and that's what I'm asking for.
« Last Edit: January 06, 2026, 11:47:25 pm by GBR »

creaothceann

  • Sr. Member
  • ****
  • Posts: 266
Re: Assigning dynamic callBack to OnTerminate ?
« Reply #1 on: January 07, 2026, 08:46:20 am »
  • You could create a new class TJob that derives from TThread, and store ID and Caption there.
  • Same with any other data that is needed during termination.
  • You have to override the TThread.Execute method anyway, so you could put the "OnTerminate" code there, or into an overridden Destroy method.
  • You're currently only adding threads to the array, not removing them. Probably not a problem in practice for modern systems...
  • The threads should be terminated at program exit (and the global array size should then be set to zero). You can call Terminate on all of them in a loop, wait until all of them have actually terminated, then free all of them. TJob.FreeOnTerminate should be false for this.
  • Be careful when interacting with the main (GUI) thread, it must be synchronized.

Code: Pascal  [Select][+][-]
  1. type
  2.         TJob = class(TThread)
  3.                 Caption : string;
  4.                 ID      : integer;
  5.  
  6.                 constructor Create (Caption_ : string;  ID_ : integer);
  7.                 procedure   Execute;  override;
  8.                 end;
  9.  
  10. var
  11.         Jobs = array of TJob;  // consider https://wiki.freepascal.org/Generics
  12.  
  13.  
  14. constructor TJob.Create(Caption_ : string;  ID_ : integer);
  15. begin
  16.         inherited Create;
  17.         Caption := Caption_;
  18.         ID      := ID_;
  19. end;
  20.  
  21.  
  22. procedure TJob.Execute;
  23. begin
  24.         repeat
  25.                 // ...
  26.         until Terminated;
  27.         ShowFinishingMsg(ID, Caption);  // alternatively put this in TJob.Destroy (probably better in case of errors)
  28. end;
« Last Edit: January 07, 2026, 08:49:19 am by creaothceann »

cdbc

  • Hero Member
  • *****
  • Posts: 2620
    • http://www.cdbc.dk
Re: Assigning dynamic callBack to OnTerminate ?
« Reply #2 on: January 07, 2026, 10:57:25 am »
Hi
Have you tried to put this:
Code: Pascal  [Select][+][-]
  1.  {$ModeSwitch anonymousfunctions}
at the top of your unit?
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12645
  • FPC developer.
Re: Assigning dynamic callBack to OnTerminate ?
« Reply #3 on: January 07, 2026, 11:18:47 am »
And in addition to the modeswitch, are you using FPC trunk (3.3.1 ?)  Anonymous methods are only in trunk.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6322
  • Compiler Developer
Re: Assigning dynamic callBack to OnTerminate ?
« Reply #4 on: January 08, 2026, 09:35:39 pm »
OnTerminate is a TNotifyEvent so you can't assign an anonymous function that captures surrounding variables. Only one that captures Self would be possible.

GBR

  • Newbie
  • Posts: 3
Re: Assigning dynamic callBack to OnTerminate ?
« Reply #5 on: January 10, 2026, 01:43:22 am »
And in addition to the modeswitch, are you using FPC trunk (3.3.1 ?)  Anonymous methods are only in trunk.

Hi
Have you tried to put this:
Code: Pascal  [Select][+][-]
  1.  {$ModeSwitch anonymousfunctions}
at the top of your unit?
Regards Benny

I've never heard about it. So you can use anonymous functions, but you need alternative compiler?

Thaddy

  • Hero Member
  • *****
  • Posts: 18729
  • To Europe: simply sell USA bonds: dollar collapses
Re: Assigning dynamic callBack to OnTerminate ?
« Reply #6 on: January 10, 2026, 08:43:42 am »
You only need the trunk compiler 3.3.1 and in objfpc mode that modeswitch.
In the Delphi modes it is enabled by default in recent trunk.
[edit]
A simple example to use a closure with threads in fpc 3.3.1
Code: Pascal  [Select][+][-]
  1. {$mode delphi}
  2. uses {$ifdef unix}cthreads, {$endif}sysutils, classes;
  3. Var
  4.   D : Integer;
  5.  
  6. Var
  7.   T1: TThread;
  8. begin
  9.   T1:=TThread.ExecuteInThread(procedure (aData:pointer)
  10.                               var
  11.                                 i:integer;
  12.                               begin
  13.                                 for I:=1 to 10 do
  14.                                 begin
  15.                                   Sleep(10*Random(30));
  16.                                   Writeln('Thread ',TThread.CurrentThread.ThreadID,' ping ',I);
  17.                                   Inc(PInteger(AData)^,i);
  18.                                 end;
  19.                                end,@d); // don't forget the variable.
  20.   Writeln('Main thread done');
  21.   T1.WaitFor;
  22. end.
« Last Edit: January 10, 2026, 01:59:28 pm by Thaddy »
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

BrunoK

  • Hero Member
  • *****
  • Posts: 766
  • Retired programmer
Re: Assigning dynamic callBack to OnTerminate ?
« Reply #7 on: January 10, 2026, 03:55:34 pm »
Attached a sample project that demonstrate using TThread.OnTerminate usage using current distribution FPC 3.2.2

PascalDragon

  • Hero Member
  • *****
  • Posts: 6322
  • Compiler Developer
Re: Assigning dynamic callBack to OnTerminate ?
« Reply #8 on: January 10, 2026, 06:43:25 pm »
I've never heard about it. So you can use anonymous functions, but you need alternative compiler?

You simply need the development version of the compiler, because no version that contains the feature has been released yet.

 

TinyPortal © 2005-2018