Conditional variable is a common concept in both user-space and kernel-space programming. IMHO, it is a little complicated synchronization mechanism. Recently, I came across Measuring context switching and memory overheads for Linux threads, and this article provides an example which I think is a good tutorial about how to understand and use conditional variable.
The parent thread code is like following:
/* parent thread */
pthread_mutex_lock(&si.mutex);
pthread_t childt;
pthread_create(&childt, NULL, threadfunc, (void*)&si);
// Each iteration of this loop will switch context from the parent to the
// child and back - two context switches. The child signals first.
......
for (int i = 0; i < NUM_ITERATIONS; ++i) {
pthread_cond_wait(&si.cv, &si.mutex);
pthread_cond_signal(&si.cv);
}
pthread_mutex_unlock(&si.mutex);
And this is the child thread code:
// The child thread signals first
pthread_mutex_lock(&si->mutex);
pthread_cond_signal(&si->cv);
for (int i = 0; i < NUM_ITERATIONS; ++i) {
pthread_cond_wait(&si->cv, &si->mutex);
pthread_cond_signal(&si->cv);
}
pthread_mutex_unlock(&si->mutex);
(1) The first takeaway is pthread_cond_signal()
must be called after pthread_cond_wait()
in timing sequence; otherwise the signal won’t be received.
Check preceding code, before launching child thread:
......
pthread_t childt;
pthread_create(&childt, NULL, threadfunc, (void*)&si);
......
The parent thread must hold mutex
first:
......
pthread_mutex_lock(&si.mutex);
......
Then in the first iteration of loop, release the mutex
and wait for notification:
......
pthread_cond_wait(&si.cv, &si.mutex);
......
This can guarantee when child thread sends signal, the parent thread is already in the wait queue:
......
pthread_mutex_lock(&si->mutex);
pthread_cond_signal(&si->cv);
......
(2) The other thing we should remember is before and after calling pthread_cond_wait()
, the current thread must hold the mutex
. I.e., before callingpthread_cond_wait()
, the current thread get the mutex
, then in pthread_cond_wait()
, put the current thread in the wait queue and release the mutex
atomically. Once another thread signals current thread, it will reacquire mutex
and return from pthread_cond_wait()
.