[Lazarus] How does one add an event to a blocking system?

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

[Lazarus] How does one add an event to a blocking system?

Bo Berglund
I need a TCP port component that can work as a non-blocking port for
receiving data. THe data arrival should trigger an event where I can
read the data.
So if I use a thread to read data from the socket, how do I signal to
the main application that data are arriving using an event?
Is there some resource available as a guide?


--
Bo Berglund
Developer in Sweden


--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Michael Schnell
On 10/21/2015 01:44 PM, Bo Berglund wrote:
> So if I use a thread to read data from the socket, how do I signal to
> the main application that data are arriving using an event?
TThread.Synchronize(), TThread.Queue()

In an "Application" (other than in a "Program" you also can use
"Application.QueueAsyncCall()".

You supposedly want to transfer Data to the main thread. Here IMHO it's
a nice idea to use Finalizers.

-Michael

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

leledumbo
Administrator
In reply to this post by Bo Berglund
> So if I use a thread to read data from the socket, how do I signal to
the main application that data are arriving using an event?

Exactly, using an event: http://www.freepascal.org/docs-html/fcl/syncobjs/tevent.html
Here's an example of how to use:
RoundRobinExample.zip
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Mark Morgan Lloyd
In reply to this post by Michael Schnell
Michael Schnell wrote:
> On 10/21/2015 01:44 PM, Bo Berglund wrote:
>> So if I use a thread to read data from the socket, how do I signal to
>> the main application that data are arriving using an event?
> TThread.Synchronize(), TThread.Queue()

Please remind us what a non-LCL program has to call to make sure that
stuff is dequeued.

> In an "Application" (other than in a "Program" you also can use
> "Application.QueueAsyncCall()".
>
> You supposedly want to transfer Data to the main thread. Here IMHO it's
> a nice idea to use Finalizers.

--
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Michael Schnell
On 10/21/2015 02:39 PM, Mark Morgan Lloyd wrote:
> TThread.Synchronize(), TThread.Queue()
>
> Please remind us what a non-LCL program has to call to make sure that
> stuff is dequeued.
CheckSynchronize()

-Michael



--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Michael Schnell
On 10/21/2015 02:42 PM, Michael Schnell wrote:
> CheckSynchronize()
>
Unfortunately there is no decent documentation on CheckSynchronize().

So in very short (and just hopefully correct):

CheckSynchronize() needs to be called by the main thread (in fact a
threat becomes the main thread _because_ it calls CheckSynchronize().

The Events thrown by other Threads via TThread.Synchronize and
TThread.Queue are executed as sub-procedures of CheckSynchronize() and
hence they are executed in the main thread and they are executed in the
order they have been queued by other threads.

It is a very bad idea to do a closed loop such as

while (TRUE) CheckSynchronize();

As this will use 100 % CPU time and hence will reduce the performance of
all other threads (and every application that is running on the processor).

That is why CheckSynchronize() provides using the parameter "Timeout",
that defines how long to wait until returning in case no event is
queued.  (0 or no parameter => return immediately)

AFAIR if an Event is in the queue same is executed and
CheckSynchronize(I) returns without checking if more Events are queued.

AFAIK the return parameter of CheckSynchronize() does not give any
decent result and needs to be ignored.

-Michael

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Mark Morgan Lloyd
In reply to this post by Michael Schnell
Michael Schnell wrote:
> On 10/21/2015 02:39 PM, Mark Morgan Lloyd wrote:
>> TThread.Synchronize(), TThread.Queue()
>>
>> Please remind us what a non-LCL program has to call to make sure that
>> stuff is dequeued.

> CheckSynchronize()

Thanks, it's one of those things I can never remember.

--
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Michael Schnell
On 10/21/2015 03:13 PM, Mark Morgan Lloyd wrote:
>
> Thanks, it's one of those things I can never remember.
Because it is an fpc rtl thingy and not really meant to be used by
Lazarus users ;-) .

-Michael

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Mark Morgan Lloyd
In reply to this post by Michael Schnell
Michael Schnell wrote:

> On 10/21/2015 02:42 PM, Michael Schnell wrote:
>> CheckSynchronize()
>>
> Unfortunately there is no decent documentation on CheckSynchronize().
>
> So in very short (and just hopefully correct):
>
> CheckSynchronize() needs to be called by the main thread (in fact a
> threat becomes the main thread _because_ it calls CheckSynchronize().
>
> The Events thrown by other Threads via TThread.Synchronize and
> TThread.Queue are executed as sub-procedures of CheckSynchronize() and
> hence they are executed in the main thread and they are executed in the
> order they have been queued by other threads.
>
> It is a very bad idea to do a closed loop such as
>
> while (TRUE) CheckSynchronize();
>
> As this will use 100 % CPU time and hence will reduce the performance of
> all other threads (and every application that is running on the processor).
>
> That is why CheckSynchronize() provides using the parameter "Timeout",
> that defines how long to wait until returning in case no event is
> queued.  (0 or no parameter => return immediately)
>
> AFAIR if an Event is in the queue same is executed and
> CheckSynchronize(I) returns without checking if more Events are queued.
>
> AFAIK the return parameter of CheckSynchronize() does not give any
> decent result and needs to be ignored.

Seems reasonable. I think I've used it in one place, which is a console
program which spends most of its time waiting for keyboard input but
also has

procedure MainThreadYield;

begin
   Assert(InterlockedExchange(mainThreadYieldEntryCounter, 1) = 0,
'MainThreadYield reentered');
{$ifndef LCL }
   CheckSynchronize;
{$endif LCL  }
   Assert(InterlockedExchange(mainThreadYieldEntryCounter, 0) = 1,
'MainThreadYield reexited')
end { MainThreadYield } ;

I don't know whether I've overlooked anything significant there, but it
appears robust and activity triggered by around half a dozen background
threads appears as expected.

--
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Michael Schnell
On 10/21/2015 04:19 PM, Mark Morgan Lloyd wrote:
>
>
> I don't know whether I've overlooked anything significant there, but
> it appears robust and activity triggered by around half a dozen
> background threads appears as expected.

Of course it's robust.

But check the CPU usage. It it's 100% all threads get just time slices-
If it's just one other thread, same will never get more than 50 %.

If it's not 100% the system is waiting somewhere else in a sleep, a
blocking read or similar.

-Michael


--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Sven Barth
In reply to this post by Michael Schnell

Am 21.10.2015 14:59 schrieb "Michael Schnell" <[hidden email]>:
> CheckSynchronize() needs to be called by the main thread (in fact a threat becomes the main thread _because_ it calls CheckSynchronize().

The part in parenthesis is wrong. CheckSynchronize checks for MainThreadID which is determined independently of CheckSynchronize.

> The Events thrown by other Threads via TThread.Synchronize and TThread.Queue are executed as sub-procedures of CheckSynchronize() and hence they are executed in the main thread and they are executed in the order they have been queued by other threads.

Better usage of terms: Exceptions are thrown (or raised), events are signaled.

> AFAIR if an Event is in the queue same is executed and CheckSynchronize(I) returns without checking if more Events are queued.

CheckSynchronize completely cwalks the lost before it returns.

> AFAIK the return parameter of CheckSynchronize() does not give any decent result and needs to be ignored.

That is indeed always "false" right now. I should check sometime what it is supposed to return... Probably whether at least one event got executed :/

Regards,
Sven


--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Mark Morgan Lloyd
In reply to this post by Michael Schnell
Michael Schnell wrote:
> On 10/21/2015 04:19 PM, Mark Morgan Lloyd wrote:
>>
>> I don't know whether I've overlooked anything significant there, but
>> it appears robust and activity triggered by around half a dozen
>> background threads appears as expected.
>
> Of course it's robust.

But my use of it might not have been.

> But check the CPU usage. It it's 100% all threads get just time slices-
> If it's just one other thread, same will never get more than 50 %.
>
> If it's not 100% the system is waiting somewhere else in a sleep, a
> blocking read or similar.

CPU usage depends on what the hardware I'm emulating is doing :-)

--
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] *SPAM* Re: How does one add an event to a blocking system?

Michael Schnell
In reply to this post by Sven Barth
On 10/21/2015 05:27 PM, Sven Barth wrote:
>
> CheckSynchronize checks for MainThreadID which is determined
> independently of CheckSynchronize.
>
I see. I suppose the would-be MainThread is just the thread that is used
to start the application. That does make sense. For the internal logic
of the Lazarus application the fact that it calls CheckSynchronize() is
what makes the difference.

> Better usage of terms: Exceptions are thrown (or raised), events are
> signaled.
You are right. "thrown" is not a good wording for Events. I mostly read
"fired" on that behalf.

> CheckSynchronize completely walks the lost before it returns.
Thanks a lot for the correction. This is very important to me (see below).

> > AFAIK the return parameter of CheckSynchronize() does not give any
> decent result and needs to be ignored.
>
> That is indeed always "false" right now. I should check sometime what
> it is supposed to return... Probably whether at least one event got
> executed :/
>

Maybe the original idea was to have CheckSynchronize execute only one
Event and return TRUE if more events up are to be handled.

With this (not existing) design, I would need to do something like:

procedure TmyApplication.ProcessMessages;
begin
while CheckSynchronize() do (*nothing*) ;
end;

With the current design just

procedure TmyApplication.ProcessMessages;
begin
CheckSynchronize();
end;

would be OK, but the code above would work, as well and maybe should be
preferred for possible future extension.

-Michael

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Mark Morgan Lloyd
Michael Schnell wrote:
> On 10/21/2015 05:27 PM, Sven Barth wrote:

>> Better usage of terms: Exceptions are thrown (or raised), events are
>> signaled.
> You are right. "thrown" is not a good wording for Events. I mostly read
> "fired" on that behalf.

"Signalled" is not a good choice IMO, because of unix-style signals and
their handlers (e.g. sending a HUP signal to a process, to get it to
re-read its configuration).

"Triggered" can have problems if a database is being used.

"Fired" seems like a fairly good choice, since it also implies immediacy.

--
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]

--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
Reply | Threaded
Open this post in threaded view
|

Re: [Lazarus] How does one add an event to a blocking system?

Sven Barth

Am 22.10.2015 10:21 schrieb "Mark Morgan Lloyd" <[hidden email]>:
>
> Michael Schnell wrote:
>
>> On 10/21/2015 05:27 PM, Sven Barth wrote:
>
>
>>> Better usage of terms: Exceptions are thrown (or raised), events are signaled.
>>
>> You are right. "thrown" is not a good wording for Events. I mostly read "fired" on that behalf.
>
>
> "Signalled" is not a good choice IMO, because of unix-style signals and their handlers (e.g. sending a HUP signal to a process, to get it to re-read its configuration).
>
> "Triggered" can have problems if a database is being used.
>
> "Fired" seems like a fairly good choice, since it also implies immediacy.

Yes, there is a bit of ambiguity with "signaled" and "fired" indeed seems best :)

Regards,
Sven


--
_______________________________________________
Lazarus mailing list
[hidden email]
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus