Subj : Re: Win32 condition variables redux To : comp.programming.threads From : Chris Thomasson Date : Tue Aug 30 2005 06:55 pm wrote: > skip down to: >>void condvar_broadcast( condvar_t *_this ) ... >> LeaveCriticalSection( &_this->mutex ); >> while ( thread ) { next = thread->next; >Note that at this point we don't hold any mutex This iteration is completly private. More on this below... >while in: >>void prv_condvar_pop( condvar_t *_this, per_thread_t *thread ) { ... >> thread->next = 0; thread->prev = 0; } >called from >>int prv_condvar_timeout( condvar_t *_this, per_thread_t *thread ) { int >>err = 0, wait = 0; LONG count = 0; EnterCriticalSection( &_this->mutex ); >>if ( thread->state ) { prv_condvar_pop( _this, thread ); > So if a thread gets a timeout just as a condvar_broadcast() is running > through the list of threads, then the thread may corrupt the list of > threads to wake, leading to threads never being woken. > To test, use this scenario: > Modify the code to insert 'Sleep(10 seconds)' just after the > LeaveCriticalSection in condvar_broadcast() > Run the following: Start N threads which do condvar_timedwait() with no > timeout. Sleep one second to ensure that they have gone asleep Start a > thread which does condvar_timedwait() with a timeout of 4 seconds > wait 1 second Start N threads which do condvar_timedwait() with no > timeout. wait 1 second perform condvar_broadcast() wait 15 seconds > check how many threads were woken. It should be 2N+1, but I believe > it will be N+1 The race-condition you describe can't happen because the broadcast function pops the entire list of nodes, sets their per_thread_t::state variables to 0, and stores the front pointer locally under the protection of the mutex. Notice how the per_thread_t::state variable is always protected by the mutex and is used to indicate whether or not a thread is in the list? How can the timeout function corrupt the list when it only pops threads that have their per_thread_t::state variables set to PER_THREAD_WAITING? I think you need to study the pseudo-code a some more... Keep this in mind: /* not in list */ per_thread_t::state == 0; /* in list */ per_thread_t::state == PER_THREAD_WAITING; ;) .