Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2015-02

TThread.Queue vs TThread.Synchronize

41 messages · 8 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys

Hi,

I've recently seen some posts in Delphi groups that the preferred way is to use TThread.Queue instead of TThread.Synchronize.

Why is that? What are the benefits?

I've look at FPC trunk and see we now have a Queue() implementation, and I adjusted a simple multi-threaded GUI example app I had. But I still don't really understand what is the benefit of Queue vs Synchronise. I still had to create a "synchronise method" which I pass in to Queue() - similar to what I did for Synchronize().

Also how is Queue() calls processed? For example to get Synchronize() to work I had to call CheckSynchronize in my main event loop. Is this also required for Queue() functionality?

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Michael Schnell
to Graeme Geldenhuys
Graeme Geldenhuys wrote
Hi, I've recently seen some posts in Delphi groups that the preferred way is to use TThread.Queue instead of TThread.Synchronize.

TThread.Queue just "fires" an Event in the main thread. This means a "mark" is set that the event handler function is to be started by the main thread. Same performs this "as soon as possible", meaning that it is done as soon as the man thread is idle (no previously scheduled Events ("fired" by threads, GUI, ...) are in the pipe any more.

TThread.Synchronize does exactly the same, only that the thread calling TThread.Synchronize is frozen after firing the event, and the event handler is enhanced by code that frees the thread after the user code of the event handler is finished.

TThread.Queue works very similar to Application.QueueAsyncCall in the LCL

Why is that? What are the benefits?

Obviously TThread.Queue does not hamper the firing thread, while TThread.Synchronize stalls it for an undefined amount of time. As a benefit TThread,Synchronize avoids imposing mutual access issues,.

-Michael

Reply by email

Mattias Gaertner
to Graeme Geldenhuys: I've recently seen some posts in Delphi groups that the preferred way is to use…
Show quoted text 6 lines
Hi, I've recently seen some posts in Delphi groups that the preferred way is to use TThread.Queue instead of TThread.Synchronize. Why is that? What are the benefits?

Synchronize waits for the main thread.
Queue does not.
Both are executed by the main thread via CheckSynchronize. Both are useful.

Show quoted text 9 lines
I've look at FPC trunk and see we now have a Queue() implementation, and I adjusted a simple multi-threaded GUI example app I had. But I still don't really understand what is the benefit of Queue vs Synchronise. I still had to create a "synchronise method" which I pass in to Queue() - similar to what I did for Synchronize(). Also how is Queue() calls processed? For example to get Synchronize() to work I had to call CheckSynchronize in my main event loop. Is this also required for Queue() functionality?

Yes.

Mattias

Reply by email

Michael Schnell
to Graeme Geldenhuys: I've recently seen some posts in Delphi groups that the preferred way is to use…
Graeme Geldenhuys wrote 6 lines
I've look at FPC trunk and see we now have a Queue() implementation, and I adjusted a simple multi-threaded GUI example app I had. But I still don't really understand what is the benefit of Queue vs Synchronise. I still had to create a "synchronise method" which I pass in to Queue() - similar to what I did for Synchronize().

I once did a testing program that checks the functionality of TThread.Synchronize, TThread.Queue and Application.QueueAsyncCall (and some other stuff) with and without attaching a GUI. Let me know if you want to have it.

Also how is Queue() calls processed? For example to get Synchronize() to work I had to call CheckSynchronize in my main event loop. Is this also required for Queue() functionality?

In the FPC RTL, "CheckSynchronize" in fact polls the Event Queue, and performs the callbacks of the Events (Queued elements) that are push upon this queue e.g. by TThread.Synchronize and TThread.Queue.

IMHO the legacy name "CheckSynchronize" is rather misleading.

Due to the "private" nature of the queue mechanism in the FPC RTL, Application.QueueAsyncCall in the RTL works completely different than TThread.Queue, (using a different Event (aka "message") queue that is unknown to the fpc RTL but implemented (or attached to) by the LCL.

I once did a "non-GUI TApplication" for the LCL that does not attach to any external GUI. It can't be "officially" released right now, as Application.QueueAsyncCall needs to push events in the said queue. This can't be done "directly", as the stuff is private in the RTL, and hence I need to wait until the next version of the RTL provides TThread.Queue that is usable for this purpose.

I once wrote a documentation on how the event queue in the fpc RTL works, but failed with the attempt to have it included in the fpc help.

-Michael

Reply by email

Graeme Geldenhuys
to Michael Schnell: TThread.Queue just "fires" an Event in the main thread. This means a "mark" is set that…
Michael Schnell wrote
TThread.Queue works very similar to Application.QueueAsyncCall in the LCL

I don't use LCL, so I'm not familiar with all its features.

Obviously TThread.Queue does not hamper the firing thread, while TThread.Synchronize stalls it for an undefined amount of time.

Ah ok, so Synchronize() is a blocking call and Queue() isn't. That would explain why some prefer Queue().

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Marcos Douglas
to Graeme Geldenhuys
Graeme Geldenhuys wrote 8 lines
On 2015-02-23 10:56, Mattias Gaertner wrote: > Synchronize waits for the main thread. > Queue does not. > Both are executed by the main thread via CheckSynchronize. > Both are useful. Many thanks for that info. It makes sense now.

+1
Thanks too.

Marcos Douglas

Reply by email

Graeme Geldenhuys
to Michael Schnell: I once did a testing program that checks the functionality of TThread.Synchronize,…
Michael Schnell wrote
Let me know if you want to have it.

Yeah please. You can email it to this email address.

I once wrote a documentation on how the event queue in the fpc RTL works, but failed with the attempt to have it included in the fpc help.

Why not add it to the Wiki then, so your efforts would not have been wasted.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Graeme Geldenhuys
to Graeme Geldenhuys: I've recently seen some posts in Delphi groups that the preferred way is to use…

Continuing on the TThread.Queue subject - is there any way to pass parameters (or record structure with basic types) to the Queue() call?

That would be super useful instead of putting thread locking on variables (for example, reading a progress value to update a GUI progress bar).

I understand that anonymous methods (something I again don't know much about) take a snapshot of local variables. So that could possibly be used with TThread.Queue() to send variable (simple data types) information? Please correct my if I am wrong - like I said, I don't really know anonymous methods or their real usage.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Sven Barth
to Graeme Geldenhuys
Graeme Geldenhuys wrote 6 lines
Continuing on the TThread.Queue subject - is there any way to pass parameters (or record structure with basic types) to the Queue() call? That would be super useful instead of putting thread locking on variables (for example, reading a progress value to update a GUI progress bar).

Currently the only method is to use fields that belong to the TThread instance.

Show quoted text 5 lines
I understand that anonymous methods (something I again don't know much about) take a snapshot of local variables. So that could possibly be used with TThread.Queue() to send variable (simple data types) information? Please correct my if I am wrong - like I said, I don't really know anonymous methods or their real usage.

In Delphi both TThread.Queue() and TThread.Synchronize() have overloads to accept anonymous functions. It would then work like this:

=== code begin ===

type
   TPrintEvent = procedure(const aMsg: String) of object;
   TMyThread = class(TThread)
   private
     fOnPrint: TPrintEvent;
   protected
     procedure Execute; override;
     property OnPrint: TPrintEvent read fOnPrint write fOnPrint;
   end;
procedure TMyThread.Execute;
var
   s: String;
begin
   s := 'Hello World';
   Queue(procedure
     begin
       fOnPrint(s);
     end);
end;

=== code end ===

In this example both "fOnPrint" and "s" would be captured by the anonymous functions and will be available even after the thread has terminated.

For FPC modes and those people that dislike the syntax of anonymous functions (and yes, I can understand those people ;) ) I hope that we'll get the following variation to work as well:

=== code begin ===

procedure TMyThread.Execute;
var
   s: String;
   procedure SyncOnPrint;
   begin
     fOnPrint(s);
   end;
begin
   s := 'Hello World';
   Queue(@SyncOnPrint);
end;

=== code end ===

Regards,
Sven

Reply by email

silvioprog
to Sven Barth

On Mon, Feb 23, 2015 at 3:23 PM, Sven Barth
wrote:
[...]=== code begin ===

Show quoted text 16 lines
procedure TMyThread.Execute; var s: String; procedure SyncOnPrint; begin fOnPrint(s); end; begin s := 'Hello World'; Queue(@SyncOnPrint); end; === code end ===

How to compile it?:

Error: Incompatible type for arg no. 1: Got "<address of procedure is nested;Register>", expected "<procedure variable type of procedure of object;Register>".

Silvio Clécio My public projects - github.com/silvioprog

Reply by email

Philippe Lévi
to silvioprog

what you want to do makes sense? I don't think so. Thread code "may not" access stack values of calling code ...

________________________________
De: em nome de silvioprog
Enviado: segunda-feira, 23 de fevereiro de 2015 15:32 Para: FPC-Pascal users discussions
Assunto: Re: [fpc-pascal] TThread.Queue vs TThread.Synchronize

On Mon, Feb 23, 2015 at 3:23 PM, Sven Barth wrote: [...]=== code begin ===

procedure TMyThread.Execute;
var
  s: String;
  procedure SyncOnPrint;
  begin
    fOnPrint(s);
  end;
begin
  s := 'Hello World';
  Queue(@SyncOnPrint);
end;

=== code end ===

How to compile it?:

Error: Incompatible type for arg no. 1: Got "<address of procedure is nested;Register>", expected "<procedure variable type of procedure of object;Register>".

Silvio Clécio My public projects - github.com/silvioprog<http://github.com/silvioprog>

Reply by email

Philippe Lévi
to Sven Barth: Currently the only method is to use fields that belong to the TThread instance. In Delphi…
I "thought" it was not possible to use local procedure address as parameter like in queue( @SyncOnPrint);
as Clecio showed ...

________________________________________
De: em nome de Sven Barth
Enviado: segunda-feira, 23 de fevereiro de 2015 15:23 Para:
Assunto: Re: [fpc-pascal] TThread.Queue vs TThread.Synchronize

Graeme Geldenhuys wrote 6 lines
Continuing on the TThread.Queue subject - is there any way to pass parameters (or record structure with basic types) to the Queue() call? That would be super useful instead of putting thread locking on variables (for example, reading a progress value to update a GUI progress bar).

Currently the only method is to use fields that belong to the TThread instance.

Show quoted text 5 lines
I understand that anonymous methods (something I again don't know much about) take a snapshot of local variables. So that could possibly be used with TThread.Queue() to send variable (simple data types) information? Please correct my if I am wrong - like I said, I don't really know anonymous methods or their real usage.

In Delphi both TThread.Queue() and TThread.Synchronize() have overloads to accept anonymous functions. It would then work like this:

=== code begin ===

type
   TPrintEvent = procedure(const aMsg: String) of object;
   TMyThread = class(TThread)
   private
     fOnPrint: TPrintEvent;
   protected
     procedure Execute; override;
     property OnPrint: TPrintEvent read fOnPrint write fOnPrint;
   end;
procedure TMyThread.Execute;
var
   s: String;
begin
   s := 'Hello World';
   Queue(procedure
     begin
       fOnPrint(s);
     end);
end;

=== code end ===

In this example both "fOnPrint" and "s" would be captured by the anonymous functions and will be available even after the thread has terminated.

For FPC modes and those people that dislike the syntax of anonymous functions (and yes, I can understand those people ;) ) I hope that we'll get the following variation to work as well:

=== code begin ===

procedure TMyThread.Execute;
var
   s: String;
   procedure SyncOnPrint;
   begin
     fOnPrint(s);
   end;
begin
   s := 'Hello World';
   Queue(@SyncOnPrint);
end;

=== code end ===

Regards,
Sven

Reply by email

Sven Barth
to silvioprog: On Mon, Feb 23, 2015 at 3:23 PM, Sven Barth [...]=== code begin === How to compile it?:…
silvioprog wrote 27 lines
On Mon, Feb 23, 2015 at 3:23 PM, Sven Barth < > wrote: [...]=== code begin === procedure TMyThread.Execute; var s: String; procedure SyncOnPrint; begin fOnPrint(s); end; begin s := 'Hello World'; Queue(@SyncOnPrint); end; === code end === How to compile it?: Error: Incompatible type for arg no. 1: Got "<address of procedure is nested;Register>", expected "<procedure variable type of procedure of object;Register>".

Did you even read this part? And especially the tense it's written in?

For FPC modes and those people that dislike the syntax of anonymous functions (and yes, I can understand those people ) I hope that we'll get the following variation to work as well:

Regards,
Sven

Reply by email

Sven Barth
to Philippe Lévi: I "thought" it was not possible to use local procedure address as parameter like in…
Philippe Lévi wrote
I "thought" it was not possible to use local procedure address as parameter like in queue( @SyncOnPrint); as Clecio showed ...

Please read the following part of my message again:

For FPC modes and those people that dislike the syntax of anonymous functions (and yes, I can understand those people ) I hope that we'll get the following variation to work as well:

Regards,
Sven

Reply by email

Philippe Lévi
to Sven Barth

may be I do not catch it well ... problem with my english understan ... may be. "we'll get" ... you mean some day it should be possible to program it? .... correct?

you mean it will be possible to use a pointer to local function in a call?

or I misunderstand ...

________________________________________
De: em nome de Sven Barth
Enviado: segunda-feira, 23 de fevereiro de 2015 16:17 Para:
Assunto: Re: [fpc-pascal] TThread.Queue vs TThread.Synchronize

Philippe Lévi wrote
I "thought" it was not possible to use local procedure address as parameter like in queue( @SyncOnPrint); as Clecio showed ...

Please read the following part of my message again:

For FPC modes and those people that dislike the syntax of anonymous functions (and yes, I can understand those people ) I hope that we'll get the following variation to work as well:

Regards,
Sven

Reply by email

silvioprog
to Philippe Lévi
Philippe Lévi wrote 31 lines
may be I do not catch it well ... problem with my english understan ... may be. "we'll get" ... you mean some day it should be possible to program it? .... correct? you mean it will be possible to use a pointer to local function in a call? or I misunderstand ... ________________________________________ De: < > em nome de Sven Barth < > Enviado: segunda-feira, 23 de fevereiro de 2015 16:17 Para: Assunto: Re: [fpc-pascal] TThread.Queue vs TThread.Synchronize On 23.02.2015 19:41, Philippe Lévi wrote: > I "thought" it was not possible to use local procedure address as parameter like in queue( @SyncOnPrint); > as Clecio showed ... Please read the following part of my message again: > > For FPC modes and those people that dislike the syntax of anonymous functions (and yes, I can understand those people ) I hope that we'll get the following variation to work as well: Regards, Sven

Oops, sorry. Just confusion on translation.

you mean it will be possible to use a pointer to local function in a call? ²

(some switch to enable this feature?)

Silvio Clécio My public projects - github.com/silvioprog

Reply by email

Sven Barth
to Philippe Lévi: may be I do not catch it well ... problem with my english understan ... may be. "we'll…
Philippe Lévi wrote 5 lines
may be I do not catch it well ... problem with my english understan ... may be. "we'll get" ... you mean some day it should be possible to program it? .... correct? you mean it will be possible to use a pointer to local function in a call? or I misunderstand ...

Yes, it's future tense. And also there's the "I hope".

Also under certain circumstances you can already pass local procedures to other functions (requires 2.7.1 or newer):

=== code begin ===

program tnested;
{$mode objfpc}{$H+}
{$modeswitch nestedprocvars}
type
   TProc = procedure is nested;
procedure WriteStr(const aMsg: String);
begin
   Writeln(aMsg);
end;
procedure AnotherTest(aProc: TProc);
begin
   aProc();
end;
procedure Test;
var
   s: String;
   procedure PrintStr;
   begin
     Writeln(s);
   end;
begin
   s := 'Hello World';
   AnotherTest(@PrintStr);
end;
begin
   Test;
end.

=== code end ===

There is however an important difference to anonymous functions: If you
- in this example - leave the scope of "Test" the variable "s" will no longer be valid. An anonymous function on the other hand will capture that variable and will allow the use of the procedure variable even later on.

E.g. the following would work with anonymous methods, but not with nested procedure variables:

=== code begin ===

type
   TStringProc = reference to procedure; // this will work
   //TStringProc = procedure is nested; // this will not work
function Test: TStringProc;
var
   s: String;
   procedure PrintStr;
   begin
     Writeln(s);
   end;
begin
   s := 'Hello World';
   Result := @PrintStr;
end;

=== code end ===

Of course the above only applies if we should managed to get local procedures supported for anonymous function variables...

Regards,
Sven

Reply by email

Sven Barth
to silvioprog: On Mon, Feb 23, 2015 at 4:24 PM, Philippe Lévi Oops, sorry. Just confusion on…
silvioprog wrote 44 lines
On Mon, Feb 23, 2015 at 4:24 PM, Philippe Lévi < > wrote: may be I do not catch it well ... problem with my english understan ... may be. "we'll get" ... you mean some day it should be possible to program it? .... correct? you mean it will be possible to use a pointer to local function in a call? or I misunderstand ... ________________________________________ De: < > em nome de Sven Barth < > Enviado: segunda-feira, 23 de fevereiro de 2015 16:17 Para: Assunto: Re: [fpc-pascal] TThread.Queue vs TThread.Synchronize On 23.02.2015 19:41, Philippe Lévi wrote: > I "thought" it was not possible to use local procedure address as parameter like in queue( @SyncOnPrint); > as Clecio showed ... Please read the following part of my message again: > > For FPC modes and those people that dislike the syntax of anonymous functions (and yes, I can understand those people ) I hope that we'll get the following variation to work as well: Regards, Sven Oops, sorry. Just confusion on translation. you mean it will be possible to use a pointer to local function in a call? ² (some switch to enable this feature?)

See the mail I just sent to the list. In short: yes, but not exactly as I presented in my example with TThread.Queue().

Regards,
Sven

Reply by email

silvioprog
to Sven Barth
Sven Barth wrote 52 lines
On 23.02.2015 20:29, silvioprog wrote: > On Mon, Feb 23, 2015 at 4:24 PM, Philippe Lévi < > > wrote: > > may be I do not catch it well ... problem with my english understan > ... may be. "we'll get" ... you mean some day it should be possible > to program it? .... correct? > > you mean it will be possible to use a pointer to local function in a > call? > > or I misunderstand ... > > ________________________________________ > De: > > < > > em nome de Sven > Barth < <mailto:pascaldragon@ > googlemail.com>> > Enviado: segunda-feira, 23 de fevereiro de 2015 16:17 > Para: > > Assunto: Re: [fpc-pascal] TThread.Queue vs TThread.Synchronize > > On 23.02.2015 19:41, Philippe Lévi wrote: > > I "thought" it was not possible to use local procedure address as > parameter like in queue( @SyncOnPrint); > > as Clecio showed ... > > Please read the following part of my message again: > > > > > For FPC modes and those people that dislike the syntax of > anonymous functions (and yes, I can understand those people ) I hope > that we'll get the following variation to work as well: > > Regards, > Sven > > > Oops, sorry. Just confusion on translation. > > you mean it will be possible to use a pointer to local function in a > call? ² > > (some switch to enable this feature?) > See the mail I just sent to the list. In short: yes, but not exactly as I presented in my example with TThread.Queue().

I saw. It is very nice. Thank you! =)

Silvio Clécio My public projects - github.com/silvioprog

Reply by email

Philippe Lévi
to silvioprog

sorry ... I still not understand the "idea".

if code in thread access a local variable (in stack) of the function where thread is issued ... it may access "something" which does not exist any more. correct?

________________________________
De: em nome de silvioprog
Enviado: segunda-feira, 23 de fevereiro de 2015 16:42 Para: FPC-Pascal users discussions
Assunto: Re: [fpc-pascal] TThread.Queue vs TThread.Synchronize

On Mon, Feb 23, 2015 at 4:39 PM, Sven Barth wrote: On 23.02.2015 20:29, silvioprog wrote:
On Mon, Feb 23, 2015 at 4:24 PM, Philippe Lévi <

wrote:

may be I do not catch it well ... problem with my english understan ... may be. "we'll get" ... you mean some day it should be possible to program it? .... correct?

you mean it will be possible to use a pointer to local function in a call?

or I misunderstand ...

________________________________________
De:

<

em nome de Sven

Barth < >
Enviado: segunda-feira, 23 de fevereiro de 2015 16:17 Para:

Assunto: Re: [fpc-pascal] TThread.Queue vs TThread.Synchronize

Philippe Lévi wrote
I "thought" it was not possible to use local procedure address as
    parameter like in queue( @SyncOnPrint);
as Clecio showed ...

Please read the following part of my message again:

For FPC modes and those people that dislike the syntax of

anonymous functions (and yes, I can understand those people ) I hope that we'll get the following variation to work as well:

Regards,
Sven

Oops, sorry. Just confusion on translation.

you mean it will be possible to use a pointer to local function in a call? ²

(some switch to enable this feature?)

See the mail I just sent to the list. In short: yes, but not exactly as I presented in my example with TThread.Queue().

I saw. It is very nice. Thank you! =)

Silvio Clécio My public projects - github.com/silvioprog<http://github.com/silvioprog>

Reply by email

Sven Barth
to Philippe Lévi
Philippe Lévi wrote 6 lines
sorry ... I still not understand the "idea". if code in thread access a local variable (in stack) of the function where thread is issued ... it may access "something" which does not exist any more. correct?

It's not about the thread, but about the scope. As long as you pass a nested procedure around and that is only stored/used as long as the procedure in which the nested procedure is declared is in scope as well everything is fine. But once the surrounding procedure exits the procedure variable is no basically no longer valid, because the stack frame of the outer procedure no longer exists.

Only anonymous functions/closures will change that.

Regards,
Sven

Reply by email

Philippe Lévi
to Sven Barth

perfect! that's what I was understanding ...

thanks.

________________________________________
De: em nome de Sven Barth
Enviado: segunda-feira, 23 de fevereiro de 2015 16:55 Para:
Assunto: Re: [fpc-pascal] TThread.Queue vs TThread.Synchronize

Philippe Lévi wrote 6 lines
sorry ... I still not understand the "idea". if code in thread access a local variable (in stack) of the function where thread is issued ... it may access "something" which does not exist any more. correct?

It's not about the thread, but about the scope. As long as you pass a nested procedure around and that is only stored/used as long as the procedure in which the nested procedure is declared is in scope as well everything is fine. But once the surrounding procedure exits the procedure variable is no basically no longer valid, because the stack frame of the outer procedure no longer exists.

Only anonymous functions/closures will change that.

Regards,
Sven

Reply by email

Graeme Geldenhuys
to Philippe Lévi: sorry ... I still not understand the "idea". if code in thread access a local variable…
Philippe Lévi wrote
if code in thread access a local variable (in stack) of the function where thread is issued ... it may access "something" which does not exist any more. correct?

Good question, and what I was trying to get at with my second question on TThread.Queue usage. As Sven mentioned in his reply (and how I understood it, but needed confirmation), anonymous methods will solve that issue - once FPC supports anonymous method usage with TThread.Queue().

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Michael Schnell
to Graeme Geldenhuys: Yeah please. You can email it to this email address. Why not add it to the Wiki then, so…
Graeme Geldenhuys wrote
Why not add it to the Wiki then, so your efforts would not have been wasted.

IMHO, as long as there is no commonly agreed and easy and to use procedure, quickly creating publicly available online and offline usable help texts for fpc and for Lazarus, any efforts on that behalf are wasted. But this is another story and not to be discussed here (see the German Lazarus forum for the most recent discussion on that issue) .

-Michael

Reply by email

Michael Schnell
to Graeme Geldenhuys: Continuing on the TThread.Queue subject - is there any way to pass parameters (or record…
Graeme Geldenhuys wrote
Continuing on the TThread.Queue subject - is there any way to pass parameters (or record structure with basic types) to the Queue() call?

On this behalf, "Application.QueuAsyncCall" is more versatile.

But it's easy with TThread.Queue, as well.

- define a class (not to be derived from TThread) that holds the data to be transferred and a procedure without parameters
- create an instance of that class
- use TThread.Queue to have the said procedure be executed by the main thread
- at the end of the said procedure do "free" (without a prefix) this will make the instance remoce itself.

-Michael

Show quoted text 5 lines
I understand that anonymous methods (something I again don't know much about) take a snapshot of local variables. So that could possibly be used with TThread.Queue() to send variable (simple data types) information? Please correct my if I am wrong - like I said, I don't really know anonymous methods or their real usage.

The algorithm above is just an anonymous method that simply is not anonymous but "named" in the usual way classes work.

-Michael

Reply by email

Mattias Gaertner
to Graeme Geldenhuys: Good question, and what I was trying to get at with my second question on TThread.Queue…
Show quoted text 9 lines
On 2015-02-23 19:49, Philippe Lévi wrote: > if code in thread access a local variable (in stack) of the function > where thread is issued ... it may access "something" which does not > exist any more. correct? Good question, and what I was trying to get at with my second question on TThread.Queue usage. As Sven mentioned in his reply (and how I understood it, but needed confirmation), anonymous methods will solve that issue - once FPC supports anonymous method usage with TThread.Queue().

I think what you mean is "closure".
The functions don't need to be "anonymous" for that.

Mattias

Reply by email

Sven Barth
to Graeme Geldenhuys

Am 24.02.2015 10:55 schrieb "Graeme Geldenhuys" <

Show quoted text 8 lines
: On 2015-02-24 09:48, Mattias Gaertner wrote: > I think what you mean is "closure". > The functions don't need to be "anonymous" for that. Good to know, and thanks for correcting me. I'll read up on both in the Delphi help. These language features are all new to me.

AFAIK Delphi doesn't use the term "closures" though conceptually anonymous functions (as implemented by Delphi) are one way to achieve them.

Regards,
Sven

Reply by email

Michael Schnell
to Sven Barth
Sven Barth wrote 6 lines
AFAIK Delphi doesn't use the term "closures" though conceptually anonymous functions (as implemented by Delphi) are one way to achieve them.

What is the advantage of using a "closure" and/or an "anonymous function" instead of just doing "free;" as the last instruction of a normal procedure of some object ?

-Michael

Reply by email

Mattias Gaertner
to Michael Schnell
Show quoted text 10 lines
On 02/24/2015 11:12 AM, Sven Barth wrote: > > > AFAIK Delphi doesn't use the term "closures" though conceptually > anonymous functions (as implemented by Delphi) are one way to achieve > them. > What is the advantage of using a "closure" and/or an "anonymous function" instead of just doing "free;" as the last instruction of a normal procedure of some object ?

The advantage of anonymous is less typing, disadvantage is easy misuse, for example adding redundancy and harder to debug.

About closures see for example:
https://en.wikipedia.org/wiki/Closure_%28computer_programming%29

Mattias

Reply by email

Sven Barth
to Michael Schnell: What is the advantage of using a "closure" and/or an "anonymous function" instead of just…
"Michael Schnell" wrote 6 lines
On 02/24/2015 11:12 AM, Sven Barth wrote: > > > > AFAIK Delphi doesn't use the term "closures" though conceptually

anonymous functions (as implemented by Delphi) are one way to achieve them.

> What is the advantage of using a "closure" and/or an "anonymous function"

instead of just doing "free;" as the last instruction of a normal procedure of some object ?

I'll comment in context to the example you gave for passing parameters to Queue/Synchronize (a custom class with a suitable public method)

Closures:
- no need to declare a special class that handles the call
- no need to allocate a class
- no need to call "Free"

And with anonymous functions:
- the functionality is defined where it is needed (inside the parameter clause of Queue/Synchronize or in case of nested procedures at least inside the same method)

Regards,
Sven

Reply by email

Michael Schnell
to Mattias Gaertner: On Tue, 24 Feb 2015 11:23:41 +0100 The advantage of anonymous is less typing,…
Mattias Gaertner wrote

Hence the "pure" closure paradigm does not need object-orientation.

For my feeling it is prone to introduce some contradiction to object-orientation and maybe such a paradigm seems not very appropriate in an object language.

Maybe a definition of a closure/anonymous-like construct with respect to objects might be invented, that auto-creates an instance of some object-type that inherits a "Closure" (or "Execute") procedure that automatically performs a free when returning.

(In that light "TThread" is a closure-Type object, as with "FreeOnTerminate = True" "Execute" is a kind of closure. :-) )

-Michael

Reply by email

Marco van de Voort
to Michael Schnell: On this behalf, "Application.QueuAsyncCall" is more versatile. But it's easy with…

In our previous episode, Michael Schnell said:

Show quoted text 7 lines
On this behalf, "Application.QueuAsyncCall" is more versatile. But it's easy with TThread.Queue, as well. - define a class (not to be derived from TThread) that holds the data to be transferred and a procedure without parameters - create an instance of that class

(where to store that instance?)

- use TThread.Queue to have the said procedure be executed by the main thread - at the end of the said procedure do "free" (without a prefix) this will make the instance remoce itself.

You need a full queue for that, since the mainthread might not run till the thread next queue()'s.

I've a simple generic threadsafe queue that I use for that.

Reply by email

Sven Barth
to Michael Schnell: Hence the "pure" closure paradigm does not need object-orientation. For my feeling it is…
"Michael Schnell" wrote 9 lines
On 02/24/2015 11:32 AM, Mattias Gaertner wrote: > > About closures see for example: > https://en.wikipedia.org/wiki/Closure_%28computer_programming%29 > Hence the "pure" closure paradigm does not need object-orientation. For my feeling it is prone to introduce some contradiction to

object-orientation and maybe such a paradigm seems not very appropriate in an object language.

Maybe a definition of a closure/anonymous-like construct with respect to

objects might be invented, that auto-creates an instance of some object-type that inherits a "Closure" (or "Execute") procedure that automatically performs a free when returning.

Internally Closures are implemented as a class implementing an interface that provides an Invoke method.

Also Object Pascal is not a pure object oriented language so I'm definitely not against non-OOP constructs. Keep also in kind though that languages like C# also have such constructs.

Regards,
Sven

Reply by email

Sven Barth
to Marco van de Voort: In our previous episode, Michael Schnell said: (where to store that instance?) You need a…
"Marco van de Voort" wrote 11 lines
In our previous episode, Michael Schnell said: > On this behalf, "Application.QueuAsyncCall" is more versatile. > > But it's easy with TThread.Queue, as well. > > - define a class (not to be derived from TThread) that holds the data > to be transferred and a procedure without parameters > - create an instance of that class (where to store that instance?)

There's no need to. You create the object and pass the objects handler method to Queue/Synchronize. The handler method then does a Free at the end.

Regards,
Sven

Reply by email

Michael Schnell
to Marco van de Voort: In our previous episode, Michael Schnell said: (where to store that instance?) You need a…
Marco van de Voort wrote 9 lines
In our previous episode, Michael Schnell said: > On this behalf, "Application.QueuAsyncCall" is more versatile. > > But it's easy with TThread.Queue, as well. > > - define a class (not to be derived from TThread) that holds the data > to be transferred and a procedure without parameters > - create an instance of that class (where to store that instance?)

Nowhere, it is implicitly "stored" via the self-pointer of the argument when calling TThread.Queue)

Show quoted text 7 lines
> - use TThread.Queue to have the said procedure be executed by the main > thread > - at the end of the said procedure do "free" (without a prefix) this > will make the instance remoce itself. You need a full queue for that, since the mainthread might not run till the thread next queue()'s.

The fpc RTL does implement a full blown queue for managing TThread.Queue and TThread.Synchronize.

-Michael

Reply by email

Marco van de Voort
to Michael Schnell

In our previous episode, Michael Schnell said:

Show quoted text 5 lines
>> will make the instance remoce itself. > You need a full queue for that, since the mainthread might not run till the > thread next queue()'s. The fpc RTL does implement a full blown queue for managing TThread.Queue and TThread.Synchronize.

But the only state in it is the self of the method to be synchronized. But that can be enough (as Sven said)

Hadn't occured to me since I'm synchronizing msgs to a certain controller context though (my "invoke" has a parameter controller and is run by the controller .execute(self))

Reply by email

Michael Schnell
to Marco van de Voort
Marco van de Voort wrote 6 lines
But the only state in it is the self of the method to be synchronized. But that can be enough (as Sven said) Hadn't occured to me since I'm synchronizing msgs to a certain controller context though (my "invoke" has a parameter controller and is run by the controller .execute(self))

Of course you need to take into account that only the members of the "Transfer-Class" themselves are queued, not anything e.g. pointed to by them.

For handling "external" data (e.g. in a TThreadList, TList or TStringList) the user needs to implement his own managing code (including Thread synchronization via TCrtiticalSection).

-Michael

Reply by email