Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

pthreads and waiting for MULTIPLE conditions

149 views
Skip to first unread message

Andy Levine

unread,
Apr 16, 1999, 3:00:00 AM4/16/99
to
I am porting some NT work I wrote a while back to the UNIX world and have
the need to use pthreads.

Is there any functionality in the pthread libraries (or elsewhere) that
allows you to wait for MULTIPLE conditions to occur. I am looking for
functionality similar to the Win32 function WaitForMultipleObjects(), which
allows you to specify an array of synchronization objects and conditions
(wait for all, wait for any, etc) to wait for.

The only implmentation I could see for this would be a polling method where
one would wait on each condition for a set amount amount of time and sleep
if the condition doesn't occur. When one lock is acquired you would move on
to the next (if ALL were required). This seems rather kludgy, as I really
don't want to waste cycles determining if an object has been signalled, I
want to wake up WHEN one has been signalled.

Thanks
Andy Levine


Kaelin Colclasure

unread,
Apr 17, 1999, 3:00:00 AM4/17/99
to
"Andy Levine" <X--andy_...@email.msn.com> writes:

If you're just talking about multiple event handles under NT, then you can
*probably* get the same functionality from pthreads -- but it will take
some doing. If you're doing anything more "interesting" with
WaitForMultipleObjects, like throwing file/socket handles into the mix,
then things get a lot more complex.

Fundamentally, pthreads only provides the ability to wait on one condition
variable. So, you need to write an abstraction that provides many "Event"
objects, but all these objects point to the same condition variable that is
awakened when any Event is signalled. And of course, the signal operation
must add the identity of the event to a deque or some such, so that multiple
events may be signalled without any of them being lost.

Turns out that once you have done this much work, you're very close to having
a general event-queue abstraction with "stateful" events for the same
computational cost. And IMO this is a *lot* more useful.

When confronted with this issue (demultiplexing multiple event types and
sources across both NT and Unix) I opted to build an emulation of Win32's
Post/GetQueuedCompletionStatus under Unix. I'm just in the final stages of
wrapping this up, but I believe it has shaped up rather well. And I have
been very pleased with the performance characteristics under Solaris so far.
[And of course this is what MS recommends for optimal performance under NT.]

Kaz Kylheku

unread,
Apr 18, 1999, 3:00:00 AM4/18/99
to
On Fri, 16 Apr 1999 14:28:31 GMT, Andy Levine <X--andy_...@email.msn.com>
wrote:

>I am porting some NT work I wrote a while back to the UNIX world and have
>the need to use pthreads.
>
>Is there any functionality in the pthread libraries (or elsewhere) that
>allows you to wait for MULTIPLE conditions to occur.

This is not needed. Think about it. You have one thread and you want to
put it to sleep. In a typical OS kernel, all processes or threads sleep
in one ``place'' at a time, such as a supend queue and whatnot.

What you are asking for is like wanting to sleep in two or more beds
at the same time. This, of course, is only possible if you are the president of
the United States.

I am looking for
>functionality similar to the Win32 function WaitForMultipleObjects(), which

That Win32 function is seriously misconceived and should be avoided even in
Win32 programming. It has problems. For example, in the case that any *one* of
the objects can wake up the thread, there is potential starvation by one object
that is constantly going off, since the function only reports one object during
one call. (Contrast this to the much cleverer POSIX select() function that
gives you a bitmap representing objects that are ready, thus avoiding
starvation.) Another problem is that this function does not scale beyond 64
objects. If you need to wait for more events or what have you, you have to
launch additional threads. For example, if you wanted to wait for 256 objects
in Win32, you would launch four threads. Each thread would wait for 64
objects. And your ``parent'' thread would do a WaitForMultipleObjects on the
four thread handles. Ugly, ugly, ugly.

Programs that use WaitForMultipleObjects often break encapsulation; you often
see a technique whereby software modules export events, in effect saying ``here
is my event, I will set it when something interesting happens''. Needless
to say, this is hard to port.

A much better approach is to keep events buried in the implementation of
something; notification can be provided much more efficiently by direct message
passing. One object should not know about the internal events and threads of
another object.

For example, suppose that you have a thread that needs to wait until some other
object completes some task, or a timer goes off. One way to do this under Win32
might be to have two events. Your thread waits on both of them using
WaitForMultipleObjects. The events are exported to other objects (such as the
timer or the worker) which do a SetEvent. In other words, the use of Win32
events is made explicit in the interfaces between objects, a clearly
portability mistake.

A better way to do this might be to have registered callbacks. When the timer
goes off, a callback is invoked back to the waiting object. When the worker
object is done doing something, a different callback is invoked. Both
callbacks can signal the same Win32 event, so your thread just needs to wait on
that single one. This model is readily supported by POSIX condition variables,
and is easier to port among different threading platforms, because it is based
on a message passing abstraction that is directly supported by C and C++,
namely function calls.

>allows you to specify an array of synchronization objects and conditions
>(wait for all, wait for any, etc) to wait for.

There is no etc: you can wait for all, or you can wait for any (with
potential starvation, requiring you to constantly permute the array
passed to WaitForMultipleObjects).

>The only implmentation I could see for this would be a polling method where
>one would wait on each condition for a set amount amount of time and sleep
>if the condition doesn't occur. When one lock is acquired you would move on
>to the next (if ALL were required). This seems rather kludgy, as I really
>don't want to waste cycles determining if an object has been signalled, I
>want to wake up WHEN one has been signalled.

You need to combine the conditions into a single one. A condition variable is
just a bed for putting threads to sleep. The real conditions are predicates
over shared data in your program. A single condition variable can be used to
wait for multiple predicates to become true; the thread which wakes up
must do a few tests, of course. If a condition variable represents too many
predicates, then a lot of testing needs to be done by each awakened thread;
in that case, you can partition the predicates and introduce additional
condition variables.


Stephen E. Halpin

unread,
Apr 18, 1999, 3:00:00 AM4/18/99
to

It makes one wonder why no system seems to have done this right. VMS and
NT are closer to the goal in that you can wait on events from a wide range
of system services (the last time I checked you couldnt select on message
queues or semaphores in *NIX, nor could you wait on things DNS queries and
the like without using other threads or processes. Waiting on distributed
file systems and error reporting in the face of partial transactions are also
major problems in *NIX.) Limitations on how many file descriptors you can
wait varies from *NIX to *NIX, but is a proglem there as well (VMS at least
allowed multiple events to pend on the same event flag, but they only allowed
you to wait on one of four event flag sets at a time. Ack.) As you mention,
NT only gives you one event back at a time, with the starvation problem
looming. Something like a select which can take on all possible events and
uses an absolute wake time and having it return the absolute time when it
returns would be a major win here on all systems.

-Steve

0 new messages