On 05/14/2013 08:34 AM, Michael Marcin wrote:
On 5/14/2013 12:46 AM, Vicente J. Botet Escriba wrote:
I have an uncommitted version where
bool count_down(unique_lock<mutex> &lk) /// pre_condition (count_.value_ > 0) { BOOST_ASSERT(count_.value_ > 0); if (--count_.value_ == 0) { lk.unlock(); count_.cond_.notify_all(); // unlocked !!! return true; } return false; }
Maybe I'm wrong and I'm doing premature optimization and it is better to use lock_guard and don't unlock before notifying. As you point it is in any case clearer.
Measures would be needed :(
Thanks for your interest,
bool count_down(unique_lock<mutex> &lk) /// pre_condition (count_.value_ > 0) { BOOST_ASSERT(count_.value_ > 0); if (--count_.value_ == 0) { lk.unlock(); ---> interleave here <--- count_.cond_.notify_all(); // unlocked !!! return true; } return false; }
What can happen with the explicit unlock? If waiting threads wake spuriously and interleave where marked above I suppose they just acquire the lock see that the counter is zero and return. Since that thread is no longer waiting on the cv it is no longer notified by notify_all. The count_down thread has to execute slightly more code (the difference between unique_lock and lock_guard).
What can happen without the explicit unlock? We'll notify the waiting threads but we still have the mutex locked. I think worst case they wake immediately, fail to acquire the lock and immediately go back to sleep. I've been led to believe that this sleep shouldn't really happen, rather the threads should spinlock for the short time until the lock is released in the unique_lock destructor. Additionally there seems to be no guarantee the waiting threads will even wake before the unique_lock destructor.
The first seems better but I am no an expert. Looking around I've found a couple of other c++ countdown latch implementations none of them seem to do this which may or more not mean anything.
You analysis is correct, and as you said the first version is preferable. I still believe those doubts are due the fact the boost::detail::counter that is not thread safe carries a condition that doesn't need to be protected hence in case like this you have the multiple choice of implementation "unlock then notify" or "notify then unlock", the thumb rule is to minimize the lock/unlock window, and in this case due the fact the condition doesn't need to be protect while the counter is then an unlock before the condition notify is preferable. Regards Gaetano Mendola