[Lazarus] TThread.Synchronize

classic Classic list List threaded Threaded
30 messages Options
12
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
Hi *,

I have form on which is button. When user clicks button OnClick event
handler is called (it is method of form). Processing of this method
takes some time say 1 minute.
In the background is operating another thread which every 10 seconds
calls Synchronize(@MyForm.MyMethod).

My understanding is that, Synchronize schedules execution of
MyForm.MyMethod to main thread, so method is not executed until control
is returned from event handler in MyForm. Right?

But in my case happens, that method is executed while execution of event
handler does not finished yet ... is it expected behavior ?
If not is there any workaroud which enables me to hold thread until
event handler finishes ?

Thanks

-Laco.

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
On 25.10.2016 13:21, LacaK via Lazarus wrote:
> I have form on which is button. When user clicks button OnClick event
> handler is called (it is method of form). Processing of this method
> takes some time say 1 minute.
> In the background is operating another thread which every 10 seconds
> calls Synchronize(@MyForm.MyMethod).
>
> My understanding is that, Synchronize schedules execution of
> MyForm.MyMethod to main thread, so method is not executed until
> control is returned from event handler in MyForm. Right?

If you don't call CheckSynchronize within MyForm.MyMethod then yes.

> But in my case happens, that method is executed while execution of
> event handler does not finished yet ... is it expected behavior ?
> If not is there any workaroud which enables me to hold thread until
> event handler finishes ?

Check for Application.ProcessMessages and CheckSynchronize calls. These
process synchronize queue, if I am not mistaken.

Ondrej
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list

On 25.10.2016 13:21, LacaK via Lazarus wrote:
> My understanding is that, Synchronize schedules execution of
> MyForm.MyMethod to main thread, so method is not executed until
> control is returned from event handler in MyForm. Right?
TThread.Synchronze pushes the procedure that is given as a parameter
(including it's Self pointer) to the event queue and then the Therad
that called TThread.Synchronize is stalled. Some time later the main
(GUI) thread will execute the scheduled procedure. When this call
returns, the thread that called TThread.Synchronize is activated.

There also is TThread.Queue that works identically, only without
stalling the thread.

> But in my case happens, that method is executed while execution of
> event handler does not finished yet ... is it expected behavior ?

What is "that method"? If same is called by the thread after
TThread.Synchronize, IMHO this can't be correct.

-Michael

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list

> If you don't call CheckSynchronize within MyForm.MyMethod then yes.
IMHO the (hardly documented)  CheckSynchronize should not be called
directly by an application that uses a Widget Type that features an
Event Queue. Here the user should do "Application.ProcessMessages", that
is decently documented.

-Michael
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list

>
>> My understanding is that, Synchronize schedules execution of
>> MyForm.MyMethod to main thread, so method is not executed until
>> control is returned from event handler in MyForm. Right?
> TThread.Synchronze pushes the procedure that is given as a parameter
> (including it's Self pointer) to the event queue and then the Therad
> that called TThread.Synchronize is stalled.
ok

> Some time later the main (GUI) thread will execute the scheduled
> procedure. When this call returns, the thread that called
> TThread.Synchronize is activated.
ok

but what is relation between "main thread" and this "sheduled procedure"
? Can "sheduled procedure" jump into execution while main thread is
still executing prior called form method ?

>
> There also is TThread.Queue that works identically, only without
> stalling the thread.
yes, but I do not want this

>
>> But in my case happens, that method is executed while execution of
>> event handler does not finished yet ... is it expected behavior ?
>
> What is "that method"? If same is called by the thread after
> TThread.Synchronize, IMHO this can't be correct.

Yes this can happen.
MyForm.MyMethod is called also from event handler and also is used in
Synchronize(@MyForm.MyMethod)
How can this happen/play role?

I have suspection that somewhere in Win32 widgetset is called
CheckSynchronize as reaction on some message or so, which releases
execution of MyForm.MyMethod ... but it is inappropriate, does not ?

-Laco.

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list

> Check for Application.ProcessMessages and CheckSynchronize calls.
> These process synchronize queue, if I am not mistaken.

I do not call CheckSynchronize nor ProcessMessages in my application.
So only any LCL component or widget set can call it in background ?

-Laco.

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list

>
>> Check for Application.ProcessMessages and CheckSynchronize calls.
>> These process synchronize queue, if I am not mistaken.
>
> I do not call CheckSynchronize nor ProcessMessages in my application.
> So only any LCL component or widget set can call it in background ?
>
 From Delphi doc:
"Synchronize causes the call specified by AMethod to be executed using
the main thread, thereby avoiding multithread conflicts.
If you are unsure whether a method call is thread-safe, call it from
within the Synchronize method to ensure that it executes in the main thread.
Execution of the current thread is suspended while the method executes
in the main thread. "

Looking from where is called CheckSynchronize:

- TWin32WidgetSet.AppProcessMessages

- win32callback.inc:
      case Msg of
       WM_NULL:
       if (Window = Win32WidgetSet.AppHandle) then
       begin
         CheckSynchronize;
         ...

Cann't something send WM_NULL to application which can as reaction run
sheduled thread ?
WM_NULL sends HandleWakeMainThread() which is handler stored in variable
WakeMainThread

Messages in win32callback are processed by "main thread" only, so
execution cann't happen while form method is executed ?

-Laco.

> -Laco.
>
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On 25.10.2016 14:12, LacaK via Lazarus wrote:
> I do not call CheckSynchronize nor ProcessMessages in my application.
> So only any LCL component or widget set can call it in background ?

It should be easy for you to set a breakpoint into MyForm.MyMethod and
check the call stack.

Ondrej
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list


On Tue, 25 Oct 2016, LacaK via Lazarus wrote:

>
>> Check for Application.ProcessMessages and CheckSynchronize calls.
>> These process synchronize queue, if I am not mistaken.
>
> I do not call CheckSynchronize nor ProcessMessages in my application.
> So only any LCL component or widget set can call it in background ?

ShowModal() for a modal form will call it.


Michael.
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list

>> I do not call CheckSynchronize nor ProcessMessages in my application.
>> So only any LCL component or widget set can call it in background ?
>
> It should be easy for you to set a breakpoint into MyForm.MyMethod and
> check the call stack.
>
But error (AV) happens only in production and only sometimes.
Is there any way how to write call stack into file ?
TIA
-Laco.

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On Tue, 25 Oct 2016 13:37:03 +0200
Michael Schnell via Lazarus <[hidden email]> wrote:

> > If you don't call CheckSynchronize within MyForm.MyMethod then yes.  
> IMHO the (hardly documented)  CheckSynchronize should not be called
> directly by an application that uses a Widget Type that features an
> Event Queue. Here the user should do "Application.ProcessMessages", that
> is decently documented.

CheckSynchronize checks the FPC thread queue.
Application.ProcessMessages calls CheckSynchronize and checks the LCL event queues.

It is not forbidden to call CheckSynchronize in a LCL application.

Mattias
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On Tue, 25 Oct 2016 15:02:06 +0200
LacaK via Lazarus <[hidden email]> wrote:

> >> I do not call CheckSynchronize nor ProcessMessages in my application.
> >> So only any LCL component or widget set can call it in background ?  
> >
> > It should be easy for you to set a breakpoint into MyForm.MyMethod and
> > check the call stack.
> >  
> But error (AV) happens only in production and only sometimes.
> Is there any way how to write call stack into file ?

You can try GetStackTrace(true) and save it string to a file. It must be
called from main thread.

Mattias
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list

>
>>
>>> Check for Application.ProcessMessages and CheckSynchronize calls.
>>> These process synchronize queue, if I am not mistaken.
>>
>> I do not call CheckSynchronize nor ProcessMessages in my application.
>> So only any LCL component or widget set can call it in background ?
>
> ShowModal() for a modal form will call it.

Ah really?
It happens in my application!

Basicaly I have one form MyForm with one background thread, which every
10 sec. checks for files in shared folder and adds them to listbox
visible to user:
procedure TRefreshFileListThread.Execute;
begin
   while not Terminated do begin
     Synchronize(@MyForm.UpdateFileList); // UpdateFileList is method
which clears listbox and then adds files in given shared folder
     Sleep(10000);
   end;

When new file is shown then user can click on button, which imports data
from this file:
Before import is shown another form with question about "Do you want
really import file XYZ ?"

Do you say, that when this "question form" is shown it can release call
to MyForm.UpdateFileList ?
Now I did quick test and it seems, that it is so!

But is it correct behavior ? IMO it is against thread safety, which
should Synchronize guarantee!
While "main thread" is executing others threads should wait in queue ...
if not fixable, then can it be documented?, because this is exception
which is not intuitive

-Laco.
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list


On Wed, 26 Oct 2016, LacaK via Lazarus wrote:

>
>>
>>>
>>>> Check for Application.ProcessMessages and CheckSynchronize calls.
>>>> These process synchronize queue, if I am not mistaken.
>>>
>>> I do not call CheckSynchronize nor ProcessMessages in my application.
>>> So only any LCL component or widget set can call it in background ?
>>
>> ShowModal() for a modal form will call it.
>
> Ah really?
> It happens in my application!

Then that is  your problem.

> But is it correct behavior ? IMO it is against thread safety, which
> should Synchronize guarantee!

The two issues are completely unrelated. The current behaviour is correct.

Nowhere is it stated or guaranteed that synchronisation cannot happen in a GUI event
handler. Any code at any time can call the GUI message loop. A modal form is
just one instance. Your code must be able to deal with this.

Michael.
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list

>>> ShowModal() for a modal form will call it.
>>
>> Ah really?
>> It happens in my application!
>
> Then that is  your problem.
:-)))

>
>> But is it correct behavior ? IMO it is against thread safety, which
>> should Synchronize guarantee!
>
> The two issues are completely unrelated. The current behaviour is
> correct.
I did test in Delphi and Delphi seems also perform synchronize upon
ShowModal

>
> Nowhere is it stated or guaranteed that synchronisation cannot happen
> in a GUI event
> handler.

But cann't happen if nobody calls ProcessMessages or CheckSynchronize
explicitly.
So if user code is executed in event handler then this execution cann't
be interrupted by thread waiting for "synchronization"

> Any code at any time can call the GUI message loop. A modal form is
> just one instance.

ModalForm is IMO one example but may be alone in LCL ... as there are no
more controls which do same, does not ?
So in my mind it is very specific case, which should be documented.
Of course there can be any user defined control which will do same ...


> Your code must be able to deal with this.
>
Yes, thanks

-Laco.

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
On Wed, 26 Oct 2016 09:49:44 +0200
LacaK via Lazarus <[hidden email]> wrote:

> >>> ShowModal() for a modal form will call it.  
>[...]
> I did test in Delphi and Delphi seems also perform synchronize upon
> ShowModal

Yes.


> > Nowhere is it stated or guaranteed that synchronisation cannot happen
> > in a GUI event
> > handler.  
>
> But cann't happen if nobody calls ProcessMessages or CheckSynchronize
> explicitly.
> So if user code is executed in event handler then this execution cann't
> be interrupted by thread waiting for "synchronization"

Yes.
Unless you call something that does call HandleMessages/ProcessMessages
or CheckSynchronize.

 
> > Any code at any time can call the GUI message loop. A modal form is
> > just one instance.  
>
> ModalForm is IMO one example but may be alone in LCL ... as there are no
> more controls which do same, does not ?

The dialogs like TOpenDialog and ShowMessage call it.
Another example is reading the Clipboard on gtk and retrieving files in
TShellTreeView.


Mattias
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
Big Thanks to all. Now I understand what is happening ... probably I wil
use critical section to block access from thread when code in main
thread is performed ...
-Laco.

>
>>>>> ShowModal() for a modal form will call it.
>> [...]
>> I did test in Delphi and Delphi seems also perform synchronize upon
>> ShowModal
> Yes.
>
>
>>> Nowhere is it stated or guaranteed that synchronisation cannot happen
>>> in a GUI event
>>> handler.
>> But cann't happen if nobody calls ProcessMessages or CheckSynchronize
>> explicitly.
>> So if user code is executed in event handler then this execution cann't
>> be interrupted by thread waiting for "synchronization"
> Yes.
> Unless you call something that does call HandleMessages/ProcessMessages
> or CheckSynchronize.
>
>  
>>> Any code at any time can call the GUI message loop. A modal form is
>>> just one instance.
>> ModalForm is IMO one example but may be alone in LCL ... as there are no
>> more controls which do same, does not ?
> The dialogs like TOpenDialog and ShowMessage call it.
> Another example is reading the Clipboard on gtk and retrieving files in
> TShellTreeView.
>
>
> Mattias
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
In reply to this post by Free Pascal - Lazarus mailing list
On 26.10.2016 07:57, LacaK via Lazarus wrote:
> procedure TRefreshFileListThread.Execute;
> begin
>   while not Terminated do begin
>     Synchronize(@MyForm.UpdateFileList); // UpdateFileList is method
> which clears listbox and then adds files in given shared folder
>     Sleep(10000);
>   end;
This only makes sense if the actual file list generation (all but the
GUI update) is done in not shown code in the thread before Synchonize is
called.

Otherwise you just could use TTimer.

Is this done that way?

-Michael

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list
Dňa 26.10.2016 o 11:17 Michael Schnell via Lazarus napísal(a):

> On 26.10.2016 07:57, LacaK via Lazarus wrote:
>> procedure TRefreshFileListThread.Execute;
>> begin
>>   while not Terminated do begin
>>     Synchronize(@MyForm.UpdateFileList); // UpdateFileList is method
>> which clears listbox and then adds files in given shared folder
>>     Sleep(10000);
>>   end;
> This only makes sense if the actual file list generation (all but the
> GUI update) is done in not shown code in the thread before Synchonize
> is called.
no.
thread code is all what you see above.
my intention was use thread only for periodical refresh of list

>
> Otherwise you just could use TTimer.
probably yes. I do not remember why I have used thread for it. May be I
do not wanted dependency on ExtCtrls ...
Btw. when TTimer is executing OnTimer method, which does not finishes
until next Interval is elapsed, is again called OnTimer ? Or next
OnTimer is performed only when prior OnTimer finished ?

-Laco.

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [Lazarus] TThread.Synchronize

Free Pascal - Lazarus mailing list


On 26.10.2016 12:02, LacaK via Lazarus wrote:
>>
>>  you just could use TTimer.
> probably yes. I do not remember why I have used thread for it. May be
> I do not wanted dependency on ExtCtrls ...
> Btw. when TTimer is executing OnTimer method, which does not finishes
> until next Interval is elapsed, is again called OnTimer ? Or next
> OnTimer is performed only when prior OnTimer finished ?
>
Using a "Worker" Thread makes sense when
  - long winding stuff (calculations, file search, database, ...) are
done in the Thread and the GUI is supposed to go on working during that time
  - you want to take advantage of multiple cores working in parallel
(e.g. for number crunching)
  - you want to wait for external events in a blocking OS Call (e.g.
Socket).

I would avoid using Threads if not decently justified, as a lot
complexity is added.

-Michael
--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus-ide.org/listinfo/lazarus
12
Loading...