Hi,
The following may be of interest to ACE users. If you have
any comments, I recommend cross-posting them to comp.programming.threads.
Doug
In article <34D19EE2...@kou3.ina.de> you write:
++ I've just read the above-mentioned paper at
++ http://www.cs.wustl.edu/~schmidt/editorial-15.html, and have a problem
++ understanding the reasoning behind "erroneous solution 1". Here's
++ a quick summary of the solution and his explanation of the problem:
++
++ // cv->events_[SIGNAL] is an auto-reset event,
++ // cv->events_[BROADCAST] is a manual-reset event.
++
++ int pthread_cond_wait (pthread_cond_t *cv,
++ pthread_mutex_t *external_mutex)
++ {
++ cv->waiters_++;
++ ::ReleaseMutex (*external_mutex);
++ int result = ::WaitForMultipleObjects
++ (2, cv->events_, FALSE, INFINITE);
++ ::WaitForSingleObject (*external_mutex, INFINITE);
++ cv->waiters_--;
++ if (result == WAIT_OBJECT_0 + BROADCAST
++ && cv->waiters_ == 0)
++ ::ResetEvent (cv->events_[BROADCAST]);
++ }
++ int pthread_cond_signal (pthread_cond_t *cv)
++ {
++ if (cv->waiters_)
++ ::SetEvent (cv->events_[SIGNAL]);
++ }
++ int pthread_cond_broadcast (pthread_cond_t *cv)
++ {
++ if (cv->waiters_)
++ ::SetEvent (cv->events_[BROADCAST]);
++ }
++
++ Dr. Schmidt claims the following possible sequence of events:
++
++ Thread C1 waits to dequeue
++ Thread C2 waits to dequeue
++ Thread S1 enqueues 2 messages and broadcasts
++ Thread S1 exits
++ Thread C1 wakes up, dequeues a message and runs
++ Thread C1 waits again, dequeues 2nd message and runs
++ Thread C1 exits
++ Thread C2 is the only thread left and blocks forever
++
++ While I can see that thread C1 may get both messages, and that
++ this may be undesirable, I can't convince myself that thread C2
++ may end up blocked forever. Won't the test for (cv->waiters == 0)
++ prevent the broadcast event from getting reset, so that eventually
++ C2 will wake up, find the queue empty and go on its merry way?.
++
++ I would propose the following solution:
++
++ int pthread_cond_wait (pthread_cond_t *cv,
++ pthread_mutex_t *external_mutex)
++ {
++ ::ReleaseMutex (*external_mutex);
++ ::WaitForMultipleObjects(2, cv->events_, FALSE, INFINITE);
++ ::WaitForSingleObject (*external_mutex, INFINITE);
++ }
++ int pthread_cond_signal (pthread_cond_t *cv)
++ {
++ ::PulseEvent (cv->events_[SIGNAL]);
++ }
++ int pthread_cond_broadcast (pthread_cond_t *cv)
++ {
++ ::PulseEvent (cv->events_[BROADCAST]);
++ }
++
++ According to the SDK docs, PulseEvent on a manual-reset Event releases
++ *all* blocked threads, then resets the event, and on an auto-reset
++ Event releases a single and resets the event. If no threads are
++ blocked, it resets the event and does nothing. This seems a lot simpler
++ than the proposed correct solution in the paper, which involves a
++ critical section, a semaphore, an event, and two state variables.
++
++ What am I missing?
++
++ --
++ ===================================================================
++ James S. Rauser raus...@kou3.ina.de
++ Ina Werk Schaeffler KG/Abt. KOU3 +49 9132 82 32 43
++ Industriestrasse 1-3 91074 Herzogenaurach, Germany
I assume that article was written before the problems I found with your
final implementation, which has even *more* subtle problems!
Pat
Hi Pat,
> I assume that article was written before the problems I found with your
> final implementation, which has even *more* subtle problems!
I updated the article to include your changes.
Thanks,
Doug