[Solved] GUI Thread programming MAC/Linux lazarus / 21-General ---------------------------------------------------------------------- Rikard_Svenningsen · 2021-02-02 15:02 I am trying to find out how to do just that. And after reading a lot of other examples i did some basic to do. I have created this code. My problem right now is I can compile on Linux and Mac osx but it only runs on Linux. On Mac it gives a Exception Signal SIGABRT. The compiler is fpc 3.2.0 on Mac and on Linux (Ubuntu). Just for info, it runs on Intel Linux ubuntu, and RPI 2. The program is not doing any useful function except show how it can be done (maybe??) Any suggestion to why it's not running on my Mac osx ?? This is the code: 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 unit unitmythread_Real;{Main unit}{$mode objfpc}{$H+}interfaceuses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls, crt,  CommenUnit;type  { TForm1 }  TForm1 = class(TForm)    Label1: TLabel;    Label2: TLabel;    StopStart: TButton;    ProgressBar1: TProgressBar;    procedure CheckProcess;    procedure FormActivate(Sender: TObject);    procedure StopStartClick(Sender: TObject);  private  public  end; var  Form1: TForm1;  Running       :Boolean;  Aborting      :Boolean;implementationuses  tHRunningProcess;{$R *.lfm} { TForm1 }Procedure TForm1.CheckProcess;begin    Application.ProcessMessages;    ProgressBar1.Position := ShareData.Pos; end;procedure TForm1.StopStartClick(Sender: TObject);begin  If not Running then  Begin    Running := true;    ShareData.Stop:=False;    {Start thread somehow}    TRProgressBar.create;  end  else  begin    Running := False;    ShareData.Stop:= True;  end;end;procedure TForm1.FormActivate(Sender: TObject);begin  Running := False;  Aborting := False;  ShareData.Min:= ProgressBar1.Min;  ShareData.Max:= ProgressBar1.Max;  ShareData.Pos:= ProgressBar1.Position;  ShareData.Stop:= False;  ShareData.StatusText:= '';  {$IFDEF UNIX}  Label1.Caption:= 'Unix / Linux type';  {$ENDIF}  {$IFDEF UseCThreads}  Label2.Caption:= 'UseThreads';  {$ENDIF}end;end. Next unit: 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 unit tHRunningProcess;{Thread unit}{$mode objfpc}{$H+}interfaceuses  Classes, SysUtils, crt, CommenUnit; Type    TRProgressBar = class(TThread)    private    protected      LShareed  : tShare;      Procedure Execute; override;    public      property Terminated; //New property (Hidden) how does that work?      // Finished can be used insted of Terminated.      Constructor Create;    end; implementationuses  unitmythread_Real;Constructor TRProgressBar.Create;begin  FreeOnTerminate := False;//Breakpoint, pause program  inherited Create(False);end; Procedure TRProgressBar.Execute;Var  i : Integer;begin  for i:= ShareData.Min to ShareData.Max do //Breakpoint don't pause program  Begin  ShareData.Pos:=i;  {This command should be place in whatever loop running}  Form1.CheckProcess;  delay(100);  If ShareData.Stop then Break; //placed in a loop  end;end;end. next Unit:unit CommenUnit;{Shared unit}{$mode objfpc}{$H+}interfaceuses  Classes, SysUtils, ComCtrls;type   //Data type for storage    tShare        = Record    Min           : Integer;    Max           : Integer;    Pos         : Integer;    Stop          : Boolean;    StatusText    : String;    ThID          : TThreadID;  End; Var  ShareData : tShare;  ThreadProg : tThread;implementationend. Next the main program: 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 program MyThread_Real; {$mode objfpc}{$H+} uses  {$IFDEF UNIX}{$IFDEF UseCThreads}  cthreads,  {$ENDIF}{$ENDIF}  Interfaces, // this includes the LCL widgetset  Forms, unitMyThread_real, tHRunningProcess, CommenUnit  { you can add units after this }; {$R *.res} begin  RequireDerivedFormResource:=True;  Application.Scaled:=True;  Application.Initialize;  Application.CreateForm(TForm1, Form1);  Application.Run;end. [Edited to add code tags!] ---------------------------------------------------------------------- bytebites · 2021-02-02 21:04 https://wiki.freepascal.org/Multithreaded_Application_Tutorial  Thread should not manipulate gui-elements directly but via synchronize-method. ---------------------------------------------------------------------- lucamar · 2021-02-02 22:50 O.T. but please, read the Forum article in the wiki, most of all the sections on how to "Use Code Tags" and "Sharing large pieces of code". Thanks ---------------------------------------------------------------------- Rikard_Svenningsen · 2021-02-03 14:04 Quote from: bytebites on February 02, 2021, 10:04:43 pmhttps://wiki.freepascal.org/Multithreaded_Application_Tutorial  Thread should not manipulate gui-elements directly but via synchronize-method. I have read that, but not found any example i could "convert" or more "understand", so I could implement it. I have been looking at the: https://wiki.freepascal.org/Multithreaded_Application_Tutorial https://www.freepascal.org/docs-html/current/prog/progse44.html https://wiki.lazarus.freepascal.org/Example_of_multi- threaded_application:_array_of_threads To figure out what and how to do it. I managed by reading all that to create a thread that actually work. But next step is to make it thread safe. Which I absolute not is able to comprehend how to do.  Maybe someone would be kind enough to rewrite this "Procedure CheckProcess" so its clear how that is done? ---------------------------------------------------------------------- Leledumbo · 2021-02-03 19:33 I don't have or use Mac, so I can't help with that. But you have the debugger, so you can debug from the IDE and get a proper stacktrace where that particular exception is raised from. ---------------------------------------------------------------------- lucamar · 2021-02-03 20:43 Quote from: Rikard_Svenningsen on February 03, 2021, 03:04:24 pmMaybe someone would be kind enough to rewrite this "Procedure CheckProcess" so its clear how that is done? It's not CheckProcess what you have to modify, but the thread's Execute method: 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 TRProgressBar.Execute;Var  i : Integer;begin  for i:= ShareData.Min to ShareData.Max do //Breakpoint don't pause program  Begin    ShareData.Pos:=i;    {This command should be place in whatever loop running}    Synchronize(Form1.CheckProcess);    delay(100);    If ShareData.Stop then Break; //placed in a loop  end;end; You should also call CheckSynchronize() some time or other in your form, which might be done for example within a TTimer's OnTimer event handler; then after the thread is started or stopped you would also start/stop the timer. ETA: I would also modify your OnActivate handler so that it's called only once; otherwise you run the risk of re-initializing SharedData when it should be prevented. Just add this line: 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 TForm1.FormActivate(Sender: TObject);begin  OnActivate := Nil;  {rest of your code here}end; ---------------------------------------------------------------------- PascalDragon · 2021-02-04 08:05 Quote from: lucamar on February 03, 2021, 09:43:49 pmYou should also call CheckSynchronize() some time or other in your form, which might be done for example within a TTimer's OnTimer event handler; then after the thread is started or stopped you would also start/stop the timer. No, this is already handled by the message loop of the LCL for each platform. ---------------------------------------------------------------------- Rikard_Svenningsen · 2021-02-04 14:41 This is amazing I got help to the thread (how to do it safe) great, thanks guys. 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 TRProgressBar.Execute;    Var      i : Integer;    begin    for i:= ShareData.Min to ShareData.Max do //Breakpoint don't pause program      Begin        ShareData.Pos:=i;        {This command should be place in whatever loop running}        Synchronize(@Form1.CheckProcess);        delay(100);        If ShareData.Stop then Break; //placed in a loop      end;    end; It seems to be a problem with the unsafe call I made, that gives problem on MAC. The suggested seems to be working on Mac + Linux Ubuntu (Intel and RPI2) Which one is best to uses or does that depend of the case? In my case, on the RPI2 I need a thread running as fast as possible, but with a small micro delay (Controlled delay).  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 Synchronize(@Form1.CheckProcess); or 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 Queue(@Form1.CheckProcess);  But one last MAC/LINUX strange problem This compile on Linux: 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 Label3.Caption:= ShareData.ThID.ToHexString; But not on MAC Same fpc compiler 3.2.0 When compiled it gives this error: 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 Compile Project, Target: MyThread_Real: Exit code 1, Errors: 3, Hints: 2unitmythread_real.pas(37,37) Error: Illegal qualifierunitmythread_real.pas(37,37) Hint: may be pointer dereference is missingunitmythread_real.pas(37,37) Error: Incompatible type for arg no. 1: Got "TThreadID", expected "TTranslateString"control.inc(5044,20) Hint: Found declaration: SetText(const TTranslateString);unitmythread_real.pas(37,37) Fatal: Syntax error, ";" expected but "identifier TOHEXSTRING" found ---------------------------------------------------------------------- marcov · 2021-02-04 15:55 IIRC on BSD like targets, thread_ids are pointer types, not integers. Cast to ptruint to workaround. ---------------------------------------------------------------------- cdbc · 2021-02-04 16:00 Hi What's wrong with "Syncronize" and "post/send-message"? Or your own protected queue... Or Application.QueueAsyncCall(@procedure,data); Regards Benny