Event loop and sleep()

A

Alo Sarv

Hi

From what I have understood from various posts in this newsgroup, writing event
loops pretty much comes down to this:

while (true) {
handleEvents();
sleep(1); // or _sleep() or nanosleep(), depending on platform
}

The problem is that sleep() sleeps at minimum the delay given, but may sleep
longer. Initially I thought this wasn't a problem, until I ran some tests:

On P4/2.6ghz/WinXP, it runs ~500 loops per second ( 2ms avg sleep)
On P4/2.6ghz/Linux 2.6.5, it runs ~250 loops per second ( 3ms avg sleep)
On Cel/400mhz/Linux 2.4.20, it runs ~30 loops per second (20ms avg sleep)

These times were measured with idle event loop, e.g. no events were
posted/handled. On the P4 system, its all good, however I'm concerned about the
30 lps on low-end systems. Since this is idle looping, as soon as I start
posting/handling large amounts of events, it will drop even lower...

I'm not sure, but doesn't that make the app extremely slow? Are there any other
event loop mechanisms besides the above? I did a fair amount of searching over
google but came up pretty emtpy-handed on the topic of writing event loops.
Perhaps someone can suggest a book / website on the topic?

Alo Sarv.
 
P

Peter van Merkerk

Alo said:
Hi

From what I have understood from various posts in this newsgroup, writing event
loops pretty much comes down to this:

while (true) {
handleEvents();
sleep(1); // or _sleep() or nanosleep(), depending on platform
}

The problem is that sleep() sleeps at minimum the delay given, but may sleep
longer. Initially I thought this wasn't a problem, until I ran some tests:

On P4/2.6ghz/WinXP, it runs ~500 loops per second ( 2ms avg sleep)
On P4/2.6ghz/Linux 2.6.5, it runs ~250 loops per second ( 3ms avg sleep)
On Cel/400mhz/Linux 2.4.20, it runs ~30 loops per second (20ms avg sleep)

These times were measured with idle event loop, e.g. no events were
posted/handled. On the P4 system, its all good, however I'm concerned about the
30 lps on low-end systems. Since this is idle looping, as soon as I start
posting/handling large amounts of events, it will drop even lower...

You are always limited to what your system can handle. Though ony 30
loops per second seems to be rather low unless there are other things
running on that system. It appears that on the slowest system you always
loose a full time-slice, which may happen if another process in
continuosly running at the same priority. What happens if you raise the
thread priority (just for the sake of testing)?

Instead of sleeping you could yield instead since you don't seem to be
interested in getting a certain delay, but only want to be nice to other
threads on the system. To yield use pthread_yield() on POSIX compliant
platforms) or Sleep(0) on Win32. Note that neither sleeping nor yielding
is efficient when the event loop has nothing to do. It still consumes
CPU cycles and causes unnecessary context switches.
I'm not sure, but doesn't that make the app extremely slow? Are there any other
event loop mechanisms besides the above? I did a fair amount of searching over
google but came up pretty emtpy-handed on the topic of writing event loops.
Perhaps someone can suggest a book / website on the topic?

Instead of polling and sleeping in the event loop it would be more
efficient to block the event loop thread until a event has actually
arrived. Depending on the OS you could use condition variables (POSIX)
or Events (Win32) for this. When a event is put into the event queue,
you signal the event loop thread to wake up. When the event loop thread
is awakened it processes all events in the event queue and after that it
waits for another event to arrive in the event queue. The advantage of
this approach is that the event loop doesn't consume CPU cycles when it
has nothing to do.

Note that your question (and my answer) has nothing to do with the C++
language, and therefore is off-topic here. Thing like threads, sleep and
yield functions are not part of the C++ standard. You may want to ask
this question in comp.programming.threads.
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Alo said:
From what I have understood from various posts in this newsgroup, writing
event loops pretty much comes down to this:

while (true) {
handleEvents();
sleep(1); // or _sleep() or nanosleep(), depending on platform
}

The problem is that sleep() sleeps at minimum the delay given, but may
sleep longer. Initially I thought this wasn't a problem, until I ran some
tests:

You can do something like this:

while (true)
{
while (pendingEvents () )
handleEvens ();
sleep (1);
}
 
J

JKop

=?ISO-8859-15?Q?Juli=E1n?= Albo posted:
You can do something like this:

while (true)
{
while (pendingEvents () )
handleEvens ();
sleep (1);
}

for (;;)
{

}


That way nothing is evalutated.

-JKop
 
X

Xenos

Alo Sarv said:
Hi

From what I have understood from various posts in this newsgroup, writing event
loops pretty much comes down to this:

while (true) {
handleEvents();
sleep(1); // or _sleep() or nanosleep(), depending on platform
}

The problem is that sleep() sleeps at minimum the delay given, but may sleep
longer. Initially I thought this wasn't a problem, until I ran some tests:

On P4/2.6ghz/WinXP, it runs ~500 loops per second ( 2ms avg sleep)
On P4/2.6ghz/Linux 2.6.5, it runs ~250 loops per second ( 3ms avg sleep)
On Cel/400mhz/Linux 2.4.20, it runs ~30 loops per second (20ms avg sleep)

These times were measured with idle event loop, e.g. no events were
posted/handled. On the P4 system, its all good, however I'm concerned about the
30 lps on low-end systems. Since this is idle looping, as soon as I start
posting/handling large amounts of events, it will drop even lower...

I'm not sure, but doesn't that make the app extremely slow? Are there any other
event loop mechanisms besides the above? I did a fair amount of searching over
google but came up pretty emtpy-handed on the topic of writing event loops.
Perhaps someone can suggest a book / website on the topic?

Alo Sarv.

You have a few of problems. First, your delay time is arbitrary. Your
times aren't necessarily different because the sleep times are different,
but will also be affected by the time it takes to handle events. If you
have to poll like this, determine the best periodicity for the process, and
implement your code to run at this rate. You have to take into account how
long handleEvents() runs and adjust your sleep time accordingly. For
example, If you decide to make your period 1 Hz, subtract the elapsed time
that handleEvents takes to run from your delay time so you always run at
about 1 Hz.

Another problem is that, depending on your system and needs, poll can be
bad. It wastes processor time and has no regard for other processes. In a
time-slicing environment, this *may* be OK. For a system that uses
cooperative mutli-tasking this is bad. No lower priority thread will be
able to run until your task sleeps.

Third, the time that messages are processed is out of synch. with the
arrival of the messages themselves. This may or may not be OK for your
needs, but it wastes a lot of time sleeping when it has events to process.
To fix this, and the second problem, you need a way to synchronize with your
message flow. If handleEvents can be made to block (go to sleep) until
there are actual events available, then the whole task becomes just loop on
the function call. The task will sleep while there are no events and
automatically wake up when there are some to be handled.

for (;;)
handleEvents();

Regards,

DrX
 
K

Kai-Uwe Bux

JKop said:
for (;;)
{

}


That way nothing is evalutated.

-JKop

Hi,


"while ( true ) { ... }" should not evaluate anything more than
"for(;;) { ... }". I checked that for g++ on my machine:

// file: for.cc
// ============

#include <iostream>

int main ( void ) {
for (;;) {
std::cout << "0";
}
}

// end of file


// file: while.cc
// ==============

#include <iostream>

int main ( void ) {
while ( true ) {
std::cout << "0";
}
}

// end of file

g++ -S for.cc
g++ -S while.cc
diff for.s while.s
1c1
< .file "for.cc"
---
.file "while.cc"


Best

Kai-Uwe Bux
 
J

Julie

Alo said:
Hi

From what I have understood from various posts in this newsgroup, writing event
loops pretty much comes down to this:

while (true) {
handleEvents();
sleep(1); // or _sleep() or nanosleep(), depending on platform
}

The problem is that sleep() sleeps at minimum the delay given, but may sleep
longer. Initially I thought this wasn't a problem, until I ran some tests:

On P4/2.6ghz/WinXP, it runs ~500 loops per second ( 2ms avg sleep)
On P4/2.6ghz/Linux 2.6.5, it runs ~250 loops per second ( 3ms avg sleep)
On Cel/400mhz/Linux 2.4.20, it runs ~30 loops per second (20ms avg sleep)

These times were measured with idle event loop, e.g. no events were
posted/handled. On the P4 system, its all good, however I'm concerned about the
30 lps on low-end systems. Since this is idle looping, as soon as I start
posting/handling large amounts of events, it will drop even lower...

I'm not sure, but doesn't that make the app extremely slow? Are there any other
event loop mechanisms besides the above? I did a fair amount of searching over
google but came up pretty emtpy-handed on the topic of writing event loops.
Perhaps someone can suggest a book / website on the topic?

Alo Sarv.

The simplest thing to do would be to handle events while there are events to
handle, rather than sleeping between each. Presuming that handleEvents()
returns true if an event has been handled, change to:

//...
while (handleEvents()) 0;
// ...
 
J

Julie

Kai-Uwe Bux said:
Hi,

"while ( true ) { ... }" should not evaluate anything more than
"for(;;) { ... }". I checked that for g++ on my machine:

// file: for.cc
// ============

#include <iostream>

int main ( void ) {
for (;;) {
std::cout << "0";
}
}

// end of file

// file: while.cc
// ==============

#include <iostream>

int main ( void ) {
while ( true ) {
std::cout << "0";
}
}

// end of file

1c1
< .file "for.cc"
---

Best

Kai-Uwe Bux

for (;;) is the suggested way to define infinite loops, mostly from a
familiarity standpoint. The truth of the matter is that there are a number of
ways to code an infinite loop, and should probably reduce down to the same
underlying machine code.
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

JKop said:
for (;;)
{

}


That way nothing is evalutated.

If your compiler evaluates something for while (true), change your compiler.
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Julie said:
for (;;) is the suggested way to define infinite loops, mostly from a

That dspends on the book you read. Some suggest while (true) istead.

I believe that any programmer with a minimal experience can identify the
intention of both forms, then debate what is better is a lose of time.
 
K

Kai-Uwe Bux

Julie said:
for (;;) is the suggested way to define infinite loops, mostly from a
familiarity standpoint. The truth of the matter is that there are a
number of ways to code an infinite loop, and should probably reduce down
to the same underlying machine code.

Although I prefer the "while ( true ) { ... }" form, I have no intention to
argue one way or the other. I just wanted to demonstrate that these two
forms should be considered strictly equivalent as there is no performance
penalty involved with either one. It is just a matter of taste.

Am I correct to assume that for(;;) is familiar because it became the
standard idiom for infinite loops in C ?


Best

Kai-Uwe
 
H

Howard

Julie said:
The simplest thing to do would be to handle events while there are events to
handle, rather than sleeping between each. Presuming that handleEvents()
returns true if an event has been handled, change to:

//...
while (handleEvents()) 0;
// ...

Actually, I believe that the purpose of sleep(1) in this kind of event loop
is to reduce the priority of the current process, allowing other processes
to get some time (such as mouse movements, window clicks, etc.). The sleep
call is needed so that the system can respond to user control, for example
to allow the whatever is supposed to break the loop to occur (such as a
mouse click on a Stop button). Failure to add that call results in a loop
that cannot be broken, as events will never get a chance to get into the
event queue.

As stated elsewhere, the loop time depends greatly on the time to actually
handle each event. And since sleep(1) lets other threads/processes get
processor time, the loop delay is also affected by the time given to other
threads/processes, if any. And yes, it *can* cause a program to slow down a
lot, if there are lots of events to handle. But that's the nature of a
multi-tasking environment. And even if it does slow down, you'd be
surprised how much can actually get done in a very short period of time.

I'd be quite suspicious about the times recorded, though, and about the
claim that there was nothing else going on to cause this poor performance
(in the third case). We don't have the code here, or know for sure under
what conditions the test was run, or what the overhead was for setting up
and later exiting the loop, or for getting the time information before and
after the loop ran. Those are all factors to consider when doing timing
tests. (Simply moving the mouse causes the event queue to receive multiple
events!)

-Howard
 
J

Julie

Howard said:
Actually, I believe that the purpose of sleep(1) in this kind of event loop
is to reduce the priority of the current process, allowing other processes
to get some time (such as mouse movements, window clicks, etc.). The sleep
call is needed so that the system can respond to user control, for example
to allow the whatever is supposed to break the loop to occur (such as a
mouse click on a Stop button). Failure to add that call results in a loop
that cannot be broken, as events will never get a chance to get into the
event queue.

Right, but the presumption is that there are only a finite number of events to
be handled, and it is typically recommend (if that presumption is the case), to
handle all events at once, and then sleep -- rather than handle one event,
sleep, repeat.

Regardless, this is _all_ very system specific, this is only a general
recommendation on how to handle events and yielding.
As stated elsewhere, the loop time depends greatly on the time to actually
handle each event. And since sleep(1) lets other threads/processes get
processor time, the loop delay is also affected by the time given to other
threads/processes, if any. And yes, it *can* cause a program to slow down a
lot, if there are lots of events to handle. But that's the nature of a
multi-tasking environment. And even if it does slow down, you'd be
surprised how much can actually get done in a very short period of time.

I'd be quite suspicious about the times recorded, though, and about the
claim that there was nothing else going on to cause this poor performance
(in the third case). We don't have the code here, or know for sure under
what conditions the test was run, or what the overhead was for setting up
and later exiting the loop, or for getting the time information before and
after the loop ran. Those are all factors to consider when doing timing
tests. (Simply moving the mouse causes the event queue to receive multiple
events!)

In all reality, it probably has more to do w/ the minimum timeslice provided by
the operating system. Some systems will dynamically change the minimum
timeslice based on the CPU speed. Again, all system specific, and not really
topical here.
 
A

Alo Sarv

I considered this, but this causes problems if I have things that I'd like to do
once during each event loop (polling sockets for data for example). The
application I'm writing this for will be having hundreds of open sockets that
need to be polled for data, and the most logical (imho) place to do it would
be once per each event loop.
Actually, I believe that the purpose of sleep(1) in this kind of event loop
is to reduce the priority of the current process, allowing other processes
to get some time (such as mouse movements, window clicks, etc.). The sleep
call is needed so that the system can respond to user control, for example
to allow the whatever is supposed to break the loop to occur (such as a
mouse click on a Stop button). Failure to add that call results in a loop
that cannot be broken, as events will never get a chance to get into the
event queue.

As stated elsewhere, the loop time depends greatly on the time to actually
handle each event. And since sleep(1) lets other threads/processes get
processor time, the loop delay is also affected by the time given to other
threads/processes, if any. And yes, it *can* cause a program to slow down a
lot, if there are lots of events to handle. But that's the nature of a
multi-tasking environment. And even if it does slow down, you'd be
surprised how much can actually get done in a very short period of time.

I'd be quite suspicious about the times recorded, though, and about the
claim that there was nothing else going on to cause this poor performance
(in the third case). We don't have the code here, or know for sure under
what conditions the test was run, or what the overhead was for setting up
and later exiting the loop, or for getting the time information before and
after the loop ran. Those are all factors to consider when doing timing
tests. (Simply moving the mouse causes the event queue to receive multiple
events!)

A more simplified test code which shows this issue goes as follows (unix only)

#include "StopWatch.h"
#include <unistd.h>
#include <iostream>
int main() {
while (true) {
StopWatch s1;
usleep(1);
std::cerr << "Sleep length: " << s1.Time() << std::endl;
}
}

StopWatch is a small time-measuring class which uses gettimeofday() (unix) to
measure the difference of times. This code shows 15-20ms sleeps. Oddly enough,
system load doesn't seem to affect how many loops were ran - idle and full load
had no effect on the sleep lengths. However, increasing the work done in the loop
itself did (as was expected). Creating 200 open network connections and polling
each of them for data during each loop dropped loops-per-sec from 500 to 5 on the
P4 system / winXP. Question is how does it affect the application's performance
in real life situation...

Alo Sarv.
 
C

Claudio Puviani

Alo Sarv said:
Hi

From what I have understood from various posts in this newsgroup, writing event
loops pretty much comes down to this:

while (true) {
handleEvents();
sleep(1); // or _sleep() or nanosleep(), depending on platform
}

There's no reason whatsoever to have a sleep() in there. On any but the most
absurdly written event-handling libraries, either the operation that gets an
event is a blocking call, or the event multiplexer is. The loop should simply be
getEvent/handleEvent with no arbitrary delay between the two.

[... irrelevant discussion of the semantics of sleep deleted ...]
Perhaps someone can suggest a book / website on the topic?

Practically all of the late Richard Stevens' books have discussions on this.

Claudio Puviani
 
H

Howard

Claudio Puviani said:
There's no reason whatsoever to have a sleep() in there. On any but the most
absurdly written event-handling libraries, either the operation that gets an
event is a blocking call, or the event multiplexer is. The loop should simply be
getEvent/handleEvent with no arbitrary delay between the two.

Yes, there is a reason. It's put there to reduce the priority of the
process such that other processes can run their event loops. Without the
sleep there (at least on Windows, which you might be referring to as one of
those absurdly-written libraries(?)), the loop hogs all the processing
power, making the system unresponsive. Try the loop with and without the
sleep in a Windows system (if you've got one), and you should be able to see
what I mean. (I don't have any idea about other systems, though.)

-Howard
 
J

Julie

Howard said:
Yes, there is a reason. It's put there to reduce the priority of the
process such that other processes can run their event loops. Without the
sleep there (at least on Windows, which you might be referring to as one of
those absurdly-written libraries(?)), the loop hogs all the processing
power, making the system unresponsive. Try the loop with and without the
sleep in a Windows system (if you've got one), and you should be able to see
what I mean. (I don't have any idea about other systems, though.)

-Howard

You didn't follow his reasoning.

In this case, the handleEvent call should:
- process any pending events
or
- block (sleep, yield, etc.) until there is an event

Under windows, the GetMessage() call *does* the above -- it either gets a
message (to be subsequently processed), or it blocks until there is a message.

There should be no need for a Sleep call in an event handler loop in most
circumstances -- that should all be handled within the get/handle/dispatch
event code.

Get it?
 
X

Xenos

Howard said:
gets

Yes, there is a reason. It's put there to reduce the priority of the
process such that other processes can run their event loops. Without the
sleep there (at least on Windows, which you might be referring to as one of
those absurdly-written libraries(?)), the loop hogs all the processing
power, making the system unresponsive. Try the loop with and without the
sleep in a Windows system (if you've got one), and you should be able to see
what I mean. (I don't have any idea about other systems, though.)

-Howard

sleep does not change the priority of a process in Window, nor in any other
system I know of.

DrX
 
H

Howard

Julie said:
You didn't follow his reasoning.

In this case, the handleEvent call should:
- process any pending events
or
- block (sleep, yield, etc.) until there is an event

Under windows, the GetMessage() call *does* the above -- it either gets a
message (to be subsequently processed), or it blocks until there is a message.

There should be no need for a Sleep call in an event handler loop in most
circumstances -- that should all be handled within the get/handle/dispatch
event code.

Get it?

Ah, got it. I may have been thinking of using PeekMessage, not GetMessage.
PeekMessage doesn't wait on events, it just checks if they exist. (And
since he doesn't describe the contents of handleEvents, I just made an
assumption, based on how I've written similar code in the past.) I just
checked GetMessage on the MSDN site, and it seems that you are correct that
system time will be released during the "wait" for incoming events.

Just to follow up on the sleep function though, the docs on MSDN say that
using sleep(0) will release the remainder of the current time slice,
allowing time for other threads of equal priority to process. Using
sleep(1) was done so that everyobdy got a chance to process their stuff
without significantly delaying the current thread. So if you're simply
polling, and not waiting as GetMessage does, it's a good thing to have
there. But apparently uneccessary with GetMessage. (And to be honest, I
never wrote such a loop in C++, only in Delphi, and damned if I know exactly
how their Application.ProcessMessages function relates to the direct Windows
API calls GetMessage or PeekMessage!)

Thanks for the clarification.

-Howard
 
A

Alo Sarv

Xenos said:
sleep does not change the priority of a process in Window, nor in any other
system I know of.

DrX

I think I failed to make my intentions clear, so let me clarify:

The application is singlethreaded, all events are received from
sockets. The purpose of sleep() was to wake up at some interval, check
if there is anything to process from sockets, and then go back to
sleep. I don't see a way to make the system blocking without coupling
event engine directly with sockets. Additionally, there might pending
jobs that take long time (checksumming files for example), that should
be done in small amounts (64k blocks for example) during event loops.
Or there could be jobs that need to be done at specific intervals (for
example, autosaving config file every 20 minutes). Thus blocking
the loop if there are no socket events isn't an option, since that
would also block those jobs. Removing the sleep() from the loop causes
the loop to run as fast as possible, thus using 100% CPU (on any
system/compiler).

One option that was pointed out in this thread was to loop around
until there are events to process, and then go to sleep for a minimum
delay. Now, if an event handler function posts a new event, that event
also needs to be processed. And if a handler for the new event also
posts a event, that one also needs to be processed, thus can cause
endless loop if the user of the event system isn't careful... Ok, this
could be countered by limiting the number of runs through event loop
w/o sleeping to some amount, after which a sleep will be forced. Can't
say I'm exactly thrilled with this solution.

Alo.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top