So I have this while-loop that does some work with multiple threads and I want it to work as long as all threads are working, something like:
while(*threads are working*) {
pthread_mutex_lock
if(stack is not empty) {
pthread_cond_broadcast
*critical work*
pthread_mutex_unlock
}
else {
pthread_cond_wait
pthread_mutex_unlock
}
I basically want this while-loop to run until ALL threads have checked if the stack is empty and are waiting in the else case. All tips are very welcome, thanks.
Remember that condition variables are simply signalling that some condition in the enclosing program has changed. The most important thing when using condition variables is to realize what that condition is and ensuring that it's modeled correctly. The condition is often also called the predicate.
In your case your threads act as both producers and consumers of work on the shared stack. If a thread runs out of work, it will enter a wait state from which it should only return if one of the following conditions is met:
The disjunction of those two conditions form your predicate.
The first condition is already modeled in the program, as you can simply inspect the stack to find out if any new work is available. The second condition however is not. You have no way of checking how many threads are currently in the wait state.
The solution is to model that condition also, which is easily done by introducing a counter:
int threads_waiting = 0;
while(true) {
pthread_mutex_lock
if(stack is not empty) {
*critical work*
if(i_pushed_some_work_on_the_stack) {
pthread_cond_broadcast // wake up any threads that have gone to sleep
// because the stack ran out of work
}
pthread_mutex_unlock
} else {
++threads_sleeping
if(threads_sleeping == number_of_threads) {
pthread_cond_broadcast // wake up any threads waiting for
// the last thread to finish
pthread_mutex_unlock // ... and we're done!
return
}
while(true) {
pthread_cond_wait
if(stack is not empty) {
// there is more work available; continue outer loop
--threads_sleeping
break;
} else if(threads_sleeping == number_of_threads) {
// everybody is done, so let's return
pthread_mutex_unlock
return
} else {
// spurious wakeup; go back to sleep
}
}
pthread_mutex_unlock
}
Note how we call pthread_cond_broadcast
whenever the predicate changes and that after returning from pthread_cond_wait
we inspect the enclosing conditions to figure out what to do next.