I'm learning about C++11 concurrency, where my only prior experience with concurrency primitives was in Operating Systems class six years ago, so be gentle, if you can.
In C++11, we can write
std::mutex m;
std::condition_variable cv;
std::queue<int> q;
void producer_thread() {
std::unique_lock<std::mutex> lock(m);
q.push(42);
cv.notify_one();
}
void consumer_thread() {
std::unique_lock<std::mutex> lock(m);
while (q.empty()) {
cv.wait(lock);
}
q.pop();
}
This works fine, but I'm offended by the need to wrap cv.wait
in a loop. The reason we need the loop is clear to me:
Consumer (inside wait()) Producer Vulture
release the lock
sleep until notified
acquire the lock
I MADE YOU A COOKIE
notify Consumer
release the lock
acquire the lock
NOM NOM NOM
release the lock
acquire the lock
return from wait()
HEY WHERE'S MY COOKIE I EATED IT
Now, I believe one of the cool things about unique_lock
is that we can pass it around, right? So it would be really elegant if we could do this instead:
Consumer (inside wait()) Producer
release the lock
sleep until notified
acquire the lock
I MADE YOU A COOKIE
notify and yield(passing the lock)
wake(receiving the lock)
return from wait()
YUM
release the lock
Now there's no way for the Vulture thread to swoop in, because the mutex remains locked all the way from I MADE YOU A COOKIE
to YUM
. Plus, if notify()
requires that you pass a lock, that's a good way to ensure that people actually lock the mutex before calling notify()
(see Signalling a condition variable (pthreads)).
I'm pretty sure that C++11 doesn't have any standard implementation of this idiom. What's the historical reason for that (is it just that pthreads didn't do it? and then why is that)? Is there a technical reason that an adventurous C++ coder couldn't implement this idiom in standard C++11, calling it perhaps my_better_condition_variable
?
I also have a vague feeling that maybe I'm reinventing semaphores, but I don't remember enough from school to know if that's accurate or not.