2015/09/29

Why WaitForMultipleObjects() is bad and why useful things seems to get lost in dark corners of internet much easier than pictures of funny cats

Some time ago, I made a small research of embedded RTOS. I also published my personal opinion about them in my second blog.

Recently I'm preparing a newspaper article and just wanted to recall some interesting point of view why Microsoft Windows WaitForMultipleObjects() functions family is a bad idea. And guess what ... I spend almost hour to find this post in the internet ... ughh

So since things like to get lost in dark corners o internet ... I insolently decided to copy-paste this post :D ... the original post can be (as time of writing this note) found here.


Author of following post is  by Kaz Kylhe Mon, 19 Apr 1999 04:00:00
Original thread name: "pthreads and waiting for MULTIPLE conditions"
Site: http://www.verycomputer.com/5_c6341d98f68da45e_1.htm


Andy Levin was asking for:

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.

Kaz Kylhe replays:

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()

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).