Consider this basic multithreading program using pthreads. We have a main thread, creating another thread that does some work.
bool done = false;
mutex m;
condition c;
void foo() {
pthread_mutex_lock(&m);
//while(!done) {
pthread_cond_wait(&c, &m);
// Spuriously wakeup while child is doing work.
// child thread has NOT unlocked the mutex yet
// Do I now own the mutex?
// or am I waiting for child to unlock it?
//}
pthread_mutex_unlock(&m);
}
void * child(void *arg) {
pthread_mutex_lock(&m);
some_intense_work(); // this work is done while mutex is held!
// the main thread spuriously wakes up
// while this work is being done
// (while this child thread is holding the mutex)
done = true;
pthread_cond_broadcast(&c);
pthread_mutex_unlock(&m);
}
int main(int argc, char *argv[]) {
pthread_t p;
pthread_create(&p, NULL, child, NULL);
foo();
}
Pretend that we implement a wait without a surrounding while-clause checking for the predicate, even though we are aware that nobody should ever do this.
Now, if, while the child thread is doing its work, a spurious wakeup occurs in the main thread, what will the status of the mutex m be? Will the main thread own it without the child unlocking it first, so that both own it?
Or does a spurious wakeup only skip the wait for the condition, but not the wait for the mutex to be freed?
The pthread_cond_wait()
call cannot 'spuriously' wake while some other thread is holding the associated mutex. When pthread_cond_wait()
returns successfully, it will have claimed the mutex, so it cannot successfully return until the mutex is available.
In your example, a spurious wake could occur because foo()
can call pthread_cond_wait()
and have the spurious wake occur before child()
ever gets a chance to call pthread_mutex_lock()
in the first place.
Another problem in your example (with the commented code left disabled) has is that it's possible for the pthread_cond_wait()
call to never wake. This scenario can happen if child()
completes all of it's processing before foo()
manages to acquire the mutex. in that scenario, child()
will call pthread_cond_broadcast()
before the main thread is waiting in pthread_cond_wait()
so the main thread will miss the broadcast. Since foo()
never checks done
while holding the mutex, it won't notice that child()
has finished its work.
That's why pthread_cond_wait()
pretty much always has to be performed in a loop that checks the condition.