Recent

Author Topic: Synchronize not working  (Read 30882 times)

GeneCode

  • New Member
  • *
  • Posts: 25
  • What is the cost of lies?
Synchronize not working
« on: November 08, 2021, 10:38:30 am »
Hi.

I have a custom thread in my app.

Code: Pascal  [Select][+][-]
  1.  MainThread := TMainPortThread.Create(True); // With the True parameter it doesn't start automatically
  2.             if Assigned(MainThread.FatalException) then
  3.             raise MainThread.FatalException;
  4.             // Here the code initialises anything required before the threads starts executing
  5.             LoopPosM := 1;
  6.             MainThread.Start;  

Here is the constructor:
Code: Pascal  [Select][+][-]
  1. constructor TMainPortThread.Create(CreateSuspended: boolean);
  2. begin
  3.   FreeOnTerminate := True;
  4.   inherited Create(CreateSuspended);
  5. end;  

The thread works fine. But I cannot figure out why the call to Synchronize does not work.
I am calling the Synchronize on one of the TMainPortThread private methods in the MainPortThread
Execute method.

Code: Pascal  [Select][+][-]
  1. Synchronize(@UpdateGUI);  

UpdateGUI:

Code: Pascal  [Select][+][-]
  1. procedure TMainPortThread.UpdateGUI;
  2. // this method is only called by Synchronize(@ShowStatus) and therefore
  3. // executed by the main thread
  4. // The main thread can access GUI elements, for example Form1.Caption.
  5. begin
  6.  
  7.   PulseGenForm.Shape2.Brush.Color:=clLime;
  8.  
  9.  if (GUIMsg='HI') then begin
  10.     WriteLn('test');
  11.  end;
  12.  
  13.  GUIMsg := '';
  14. end;  

I can see in console, test is printed. That means this function is being called, but
the Shape2 color never changed.  %)

If you need other details let me know then i can add here. I am continuing to debug this.
Windows 10
Lazarus 1.8.4

loaded

  • Hero Member
  • *****
  • Posts: 824
Re: Synchronize not working
« Reply #1 on: November 08, 2021, 11:33:18 am »
Hi,
I have a working example on the subject;

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  9.  
  10. type
  11.  
  12.   { T_f_SecT }
  13.   T_f_SecT = class(TThread)
  14.   private
  15.     procedure Synchronous;
  16.   protected
  17.     procedure Execute; override;
  18.   end;
  19.  
  20.   { TForm1 }
  21.  
  22.   TForm1 = class(TForm)
  23.     Button1: TButton;
  24.     procedure Button1Click(Sender: TObject);
  25.   private
  26.  
  27.   public
  28.  
  29.   end;
  30.  
  31. var
  32.   Form1: TForm1;
  33.   d:Double=0;
  34. implementation
  35.  
  36. {$R *.lfm}
  37.  
  38. { For Thread }
  39. procedure T_f_SecT.Synchronous;
  40. begin
  41.  Showmessage('Thread Synchronous Sum d :' + floattostr(d));
  42. end;
  43.  
  44. procedure T_f_SecT.Execute;
  45. var
  46.   i:integer;
  47.  
  48. begin
  49.  for i:=0 to high(Integer) do
  50.  begin
  51.  d:=d+i;
  52.  end;
  53.  Synchronize(@Synchronous);
  54. end;
  55.  
  56. { TForm1 }
  57.  
  58. procedure TForm1.Button1Click(Sender: TObject);
  59. var
  60.   Zcounter : T_f_SecT;
  61. begin
  62.   Zcounter:=T_f_SecT.Create(false);
  63. end;
  64.  
  65. end.
  66.  
Check out  loaded on Strava
https://www.strava.com/athletes/109391137

devEric69

  • Hero Member
  • *****
  • Posts: 648
Re: Synchronize not working
« Reply #2 on: November 08, 2021, 11:59:50 am »
Hello,

Your method UpdateGUI should be part of your TForm. The " main thread " that can access GUI elements, for example Form1.Caption, ..., is managing the ...TForm's methods to Invalidate, Update, Paint its GUI controls (overall).
« Last Edit: November 08, 2021, 12:03:23 pm by devEric69 »
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Synchronize not working
« Reply #3 on: November 08, 2021, 01:31:04 pm »
Code: Pascal  [Select][+][-]
  1.  MainThread := TMainPortThread.Create(True); // With the True parameter it doesn't start automatically
  2.             if Assigned(MainThread.FatalException) then
  3.             raise MainThread.FatalException;
  4.             // Here the code initialises anything required before the threads starts executing
  5.             LoopPosM := 1;
  6.             MainThread.Start;  

Side note: you only need to check FatalException after the execution of the thread, but since you're using FreeOnTerminate that's not possible anyway.

UpdateGUI:

Code: Pascal  [Select][+][-]
  1. procedure TMainPortThread.UpdateGUI;
  2. // this method is only called by Synchronize(@ShowStatus) and therefore
  3. // executed by the main thread
  4. // The main thread can access GUI elements, for example Form1.Caption.
  5. begin
  6.  
  7.   PulseGenForm.Shape2.Brush.Color:=clLime;
  8.  
  9.  if (GUIMsg='HI') then begin
  10.     WriteLn('test');
  11.  end;
  12.  
  13.  GUIMsg := '';
  14. end;  

I can see in console, test is printed. That means this function is being called, but
the Shape2 color never changed.  %)

Then the problem is probably with the shape, but definitely not with the Synchronize. Does it work if you call the same code from e.g. a timer?

Your method UpdateGUI should be part of your TForm. The " main thread " that can access GUI elements, for example Form1.Caption, ..., is managing the ...TForm's methods to Invalidate, Update, Paint its GUI controls (overall).

That's of course a nicer separation of concerns, but simply from the point-of-view of the execution it doesn't matter whether the code is part of the thread or the form (as long as the thread only calls it only using Synchronize or Queue).

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Synchronize not working
« Reply #4 on: November 08, 2021, 02:14:16 pm »
That's of course a nicer separation of concerns, but simply from the point-of-view of the execution it doesn't matter whether the code is part of the thread or the form (as long as the thread only calls it only using Synchronize or Queue).

Thanks for that, had me worried.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

devEric69

  • Hero Member
  • *****
  • Posts: 648
Re: Synchronize not working
« Reply #5 on: November 08, 2021, 02:56:55 pm »
@MarkMLl: sorry for the worry.
@GeneCode: try adding an Application.ProcessMessages at the end of your method UpdateGUI.
use: Linux 64 bits (Ubuntu 20.04 LTS).
Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Synchronize not working
« Reply #6 on: November 08, 2021, 03:13:55 pm »
@MarkMLl: sorry for the worry.
@GeneCode: try adding an Application.ProcessMessages at the end of your method UpdateGUI.

No problem :-) I usually put it in the thread object since it's the neatest way of isolating any temporaries.

Agree with your point about the APM... in conjunction with Synchronize() but not with anything asynchronous which can cause recursion, and in any event it can take a lot of time if called repeatedly.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Synchronize not working
« Reply #7 on: November 08, 2021, 05:08:11 pm »
 PulseGenForm.Shape2.Brush.Color changed the color for the next draw. But you don't draw anywhere?

GeneCode

  • New Member
  • *
  • Posts: 25
  • What is the cost of lies?
Re: Synchronize not working
« Reply #8 on: November 12, 2021, 11:38:43 am »

Side note: you only need to check FatalException after the execution of the thread, but since you're using FreeOnTerminate that's not possible anyway.

Thanks for the note. That make sense.

Then the problem is probably with the shape, but definitely not with the Synchronize. Does it work if you call the same code from e.g. a timer?

That's the thing, Shape does change color when I call from timer. It is just not changing with the Synchronize.

PulseGenForm.Shape2.Brush.Color changed the color for the next draw. But you don't draw anywhere?

I don't need to call draw because Synchronize is supposed to run the method in main program thread, no?

Anyway...

I think I saw a break that might have skipped that Synchronize call altogether. In which case a brain fart part of mine.
I'll check it further and get back here if that was the case.
« Last Edit: November 12, 2021, 11:52:37 am by GeneCode »
Windows 10
Lazarus 1.8.4

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Synchronize not working
« Reply #9 on: November 12, 2021, 02:45:55 pm »
PulseGenForm.Shape2.Brush.Color changed the color for the next draw. But you don't draw anywhere?

I don't need to call draw because Synchronize is supposed to run the method in main program thread, no?

True, and afaik it will set the brush color for the next draw to the specified color. But I suspect that doesn't trigger a redraw of whatever you draw.

Anyway...

I think I saw a break that might have skipped that Synchronize call altogether. In which case a brain fart part of mine.
I'll check it further and get back here if that was the case.
[/quote]

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 1313
Re: Synchronize not working
« Reply #10 on: November 12, 2021, 04:10:32 pm »
@MarkMLl: sorry for the worry.
@GeneCode: try adding an Application.ProcessMessages at the end of your method UpdateGUI.
Sleep(0) or Sleep(1) is often a better alternative of ProcessMessages.

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Synchronize not working
« Reply #11 on: November 12, 2021, 04:33:50 pm »
Sleep(0) or Sleep(1) is often a better alternative of ProcessMessages.
Just an "academic" observation. Sleep() and ProcessMessages are two very different things.  A call to Sleep() has nothing to do with processing messages and, calling Sleep in a UI thread is, more often than not, a bad idea because it delays the repainting of the window.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Synchronize not working
« Reply #12 on: November 12, 2021, 04:36:59 pm »
Sleep(0) or Sleep(1) is often a better alternative of ProcessMessages.

Are you absolutely sure of that? Application.ProcessMessages specifically causes the message queue to be checked, while Sleep() simply withholds the CPU for some number of mSec.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

cdbc

  • Hero Member
  • *****
  • Posts: 1027
    • http://www.cdbc.dk
Re: Synchronize not working
« Reply #13 on: November 12, 2021, 05:39:37 pm »
Hi
Have a look at Postmessage / Sendmessage...
From thread to main...
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

GeneCode

  • New Member
  • *
  • Posts: 25
  • What is the cost of lies?
Re: Synchronize not working
« Reply #14 on: November 17, 2021, 08:15:09 am »
Just an "academic" observation. Sleep() and ProcessMessages are two very different things.  A call to Sleep() has nothing to do with processing messages and, calling Sleep in a UI thread is, more often than not, a bad idea because it delays the repainting of the window.

I agree with you. Sleep will block the UI thread for sure.

Hi
Have a look at Postmessage / Sendmessage...
From thread to main...
Regards Benny

Thanks for your suggestion, but I really don't want a too complicated solution.
Synchronize should've worked.


_____________________________________

Anyway, I was able to reproduce the problem in a test application.
It seems the Synchronize failed only in the child form. :o In the main form, it works well.

You can try it in a crude app I made. Pls ignore code quality  :P
Ps. I *THINK* my code is right. But if you find bug do let me know. Otherwise I am baffled as to why the UI is not updating in Synchronized methods in child form only.
« Last Edit: November 17, 2021, 08:38:04 am by GeneCode »
Windows 10
Lazarus 1.8.4

 

TinyPortal © 2005-2018