2015-12-13 - condition variable and lock

some time ago i was asked to make a code review of a multi-threaded code part. i found a code block like this:

std::condition_variable cv;
std::mutex              m;
// ...a lot of code here...
std::unique_lock<std::mutex> lock(m);
cv.notify_one();

and commented it as a “no-no” – why to notify, while still having mutex locked?! it's obvious other thread will do something like this:

std::unique_lock<std::mutex> lock(m);
cv.wait(lock, someConditionCheck);
// ... now process

so it means we're waking up a thread, just so it can block on mutex, then we unlock and wake it up again, so that it can process. sounds like a waste, doesn't it?

well – it appears it does not work that way. in fact POSIX advises signaling under a lock. dunno what are implementation details here, but doing this:

m.lock();
// ...
cv.notify_one();
m.unlock();

performs better than this:

m.lock()
// ...
m.unlock();
cv.notify_one();

which was quite surprising for me.

in fact the gain for linux system was ~3-10% (depending on the particular run and the machine test were run on), while at my friend's windows platform difference was as high as 30% (reference implementation)!

even though i still do not know why it is so, the good news is that naturally written RAII code:

std::lock_guard<std::mutex> lock(m);
// ...
cv.notify_one();

works as expected and is superior, when it comes to performance.