Recent

Author Topic: Problem with multi-thread in newer FPC  (Read 2884 times)

fdsingleton

  • New Member
  • *
  • Posts: 31
Problem with multi-thread in newer FPC
« on: September 24, 2017, 06:35:23 am »
I am not at all an expert at object-oriented Pascal and the LCL, but I have been running the same program for
years on 32-bit Windows with separate threads for a long calculation which occasionally needs to
communicate with the main thread i.e. mouse to cancel and logging on screen.  This worked including with
the Lazarus which used FPC 2.6.4.  Recently I have been trying to update my Lazarus so was trying
to use FPC 3.0.2. However the thread communication procedure Synchronize is apparently different
now.  The help system says it needs 2 parameters instead of 1.  When I give it my guess as to
what the 2 parameters should be, it still has an error.  The following is a short code section
and the error messages.
         .
         .
    procedure TNewtThread.DoWriteLog;
    begin
      _LogString;
    end;             

    procedure TDynThread.DoWriteLog;
    begin
      _LogString;
    end;

    procedure TNewtThread.DoWrite;  {This appears to be a new parameter set for Synchronize}
    begin
140    Synchronize(TNewtThread,TNewtThread.DoWriteLog);
    end;
    procedure TDynThread.DoWrite;
    begin
       Synchronize(TDynThread.DoWriteLog); {This is the old form which has been used for years}
145 end;   

           .
           .
Messages:

DUnit1.pas(140,50)Error: Only class methods, class properties, and class variables can be accessed in class methods
DUnit1.pas(140,50)Error: Only class methods, class properties, and class variables can be referred with class methods
DUnit1.pas(144,37)Error: Only class methods, class properties, and class variables can be accessed in class methods
DUnit1.pas(144,37)Error: Only class methods, class properties, and class variables can be referred with class methods

etc.

Help!

bytebites

  • Hero Member
  • *****
  • Posts: 633
Re: Problem with multi-thread in newer FPC
« Reply #1 on: September 24, 2017, 07:37:56 am »
  _LogString is not class method

Code: Pascal  [Select][+][-]
  1. Synchronize(TNewtThread,TNewtThread.DoWriteLog)

You are using class methods and not instanced method

Code: Pascal  [Select][+][-]
  1. Synchronize(NewtThread,NewtThread.DoWriteLog)

fdsingleton

  • New Member
  • *
  • Posts: 31
Re: Problem with multi-thread in newer FPC
« Reply #2 on: September 25, 2017, 05:30:19 am »
OK, it seems that I was not declaring Delphi mode, whereas in all previous work I was.

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: Problem with multi-thread in newer FPC
« Reply #3 on: September 25, 2017, 06:19:04 am »
However the thread communication procedure Synchronize is apparently different
now.  The help system says it needs 2 parameters instead of 1.
Huh ?

OK, it seems that I was not declaring Delphi mode, whereas in all previous work I was.
bytebites answer makes much more sense to me and switching modes does not help you fix faulty code one bit (no offense). There is no indication in your snippet whatsoever that these procedures are class procedures, yet you seem to use them as such.
« Last Edit: September 25, 2017, 06:29:28 am by molly »

wadman

  • New Member
  • *
  • Posts: 37
    • wadman's home
Re: Problem with multi-thread in newer FPC
« Reply #4 on: September 27, 2017, 03:50:57 pm »
U can try my component TWCThread http://forum.lazarus.freepascal.org/index.php/topic,34505.0.html


Example of use:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3.  
  4. {$mode delphi}{$H+}
  5.  
  6.  
  7. interface
  8.  
  9.  
  10. uses
  11.     Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, wcthread, wthread;
  12.  
  13.  
  14. const
  15.      MESSAGE_LOG       = 100;
  16.  
  17.  
  18. type
  19.  
  20.  
  21.     { TForm1 }
  22.  
  23.  
  24.     TForm1 = class(TForm)
  25.         Button1: TButton;
  26.         SomeTask: TTask;
  27.         Memo1: TMemo;
  28.         WCThread1: TWCThread;
  29.         procedure Button1Click(Sender: TObject);
  30.         procedure FormDestroy(Sender: TObject);
  31.         procedure SomeTaskExecute(const Sender: TTask; const Msg: Word; var Param: Variant);
  32.         procedure SomeTaskFinish(const Sender: TTask; const Msg: Word; const Param: Variant);
  33.         procedure TaskMessage(const Sender: TTask; const Msg: Word; const Parameter: Variant);
  34.     private
  35.         procedure AddToLog(const AText: string);
  36.     public
  37.     end;
  38.  
  39.  
  40. var
  41.     Form1: TForm1;
  42.  
  43.  
  44. implementation
  45.  
  46.  
  47. {$R *.lfm}
  48.  
  49.  
  50. uses dateutils;
  51.  
  52.  
  53. { TForm1 }
  54.  
  55.  
  56. procedure TForm1.TaskMessage(const Sender: TTask; const Msg: Word; const Parameter: Variant);
  57. begin
  58.     // message from another thread
  59.     case Msg of
  60.         MESSAGE_LOG: begin
  61.             AddToLog(Parameter);
  62.         end;
  63.     end;
  64. end;
  65.  
  66.  
  67. procedure TForm1.AddToLog(const AText: string);
  68. begin
  69.     // log to memo
  70.     Memo1.Lines.Add(Format('%s : %s', [FormatDateTime('mm:nn:ss.zzz', Now), AText]));
  71. end;
  72.  
  73.  
  74. procedure TForm1.SomeTaskExecute(const Sender: TTask; const Msg: Word; var Param: Variant);
  75. begin
  76.     // another thread, "running" and send log to main thread
  77.     while Sender.IsRunning do begin
  78.         Sender.PostMessage(MESSAGE_LOG, Format('%s executed.', [Sender.Name]));
  79.         Sender.WaitMs(1000);
  80.     end;
  81. end;
  82.  
  83.  
  84. procedure TForm1.SomeTaskFinish(const Sender: TTask; const Msg: Word; const Param: Variant);
  85. begin
  86.     // add log string to memo when the task was successfully executed (not interrupted)
  87.     AddToLog(Format('%s finished.', [Sender.Name]));
  88. end;
  89.  
  90.  
  91. procedure TForm1.Button1Click(Sender: TObject);
  92. begin
  93.     // start&stop task
  94.     if not SomeTask.IsRunning then begin
  95.         SomeTask.Start;
  96.         Button1.Caption := 'Cancel';
  97.     end else begin
  98.         SomeTask.Stop;
  99.         Button1.Caption := 'Start';
  100.     end;
  101. end;
  102.  
  103.  
  104. procedure TForm1.FormDestroy(Sender: TObject);
  105. begin
  106.     // stop all tasks, fire "terminated" and IsRunning ^^ return false
  107.     WCThread1.FinishAllTasks(0);
  108. end;
  109.  
  110.  
  111. end.
  112.  

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Problem with multi-thread in newer FPC
« Reply #5 on: September 29, 2017, 09:47:25 pm »
I am not at all an expert at object-oriented Pascal and the LCL, but I have been running the same program for
years on 32-bit Windows with separate threads for a long calculation which occasionally needs to
communicate with the main thread i.e. mouse to cancel and logging on screen.  This worked including with
the Lazarus which used FPC 2.6.4.  Recently I have been trying to update my Lazarus so was trying
to use FPC 3.0.2. However the thread communication procedure Synchronize is apparently different
now.  The help system says it needs 2 parameters instead of 1.  When I give it my guess as to
what the 2 parameters should be, it still has an error.  The following is a short code section
and the error messages.

This is not correct. The Synchronize() with only one parameter still exists, it's a protected method of TThread. So this should still work:

Code: Pascal  [Select][+][-]
  1. procedure TNewThread.DoWrite;
  2. begin
  3.   Synchronize(DoWrite);
  4. end;
  5.  

Code: Pascal  [Select][+][-]
  1.     procedure TNewtThread.DoWriteLog;
  2.     begin
  3.       _LogString;
  4.     end;            
  5.  
  6.     procedure TDynThread.DoWriteLog;
  7.     begin
  8.       _LogString;
  9.     end;
  10.  
  11.     procedure TNewtThread.DoWrite;  {This appears to be a new parameter set for Synchronize}
  12.     begin
  13. 140    Synchronize(TNewtThread,TNewtThread.DoWriteLog);
  14.     end;
  15.     procedure TDynThread.DoWrite;
  16.     begin
  17.        Synchronize(TDynThread.DoWriteLog); {This is the old form which has been used for years}
  18. 145 end;  
  19.  

Messages:

DUnit1.pas(140,50)Error: Only class methods, class properties, and class variables can be accessed in class methods
DUnit1.pas(140,50)Error: Only class methods, class properties, and class variables can be referred with class methods
DUnit1.pas(144,37)Error: Only class methods, class properties, and class variables can be accessed in class methods
DUnit1.pas(144,37)Error: Only class methods, class properties, and class variables can be referred with class methods

And even if you use the variant with two parameters you need to use an instance here instead of the class type:

Code: Pascal  [Select][+][-]
  1. procedure TNewThread.DoWrite;
  2. begin
  3.   Synchronize(Self, DoWrite);
  4. end;
  5.  

Note: If you use mode ObjFPC instead of mode Delphi you'll need to use "@DoWrite" in both cases.

 

TinyPortal © 2005-2018