Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

libc++ implementation of std::condition_variable_any

Condition variables should have have a single order with respect to notify() and unlock_sleep() (an imaginary function call used within wait() where the mutex is unlocked and the thread sleeps as one atomic sequence of operations) operations. To achieve this with arbitrary lockables std::condition_variable_any implementations typically use another mutex internally (to ensure atomicity and to sleep on)

If the internal unlock_sleep() and notify() (notify_one() or notify_all()) operations are not atomic with respect to each other you risk a thread unlocking the mutex, another thread signaling and then the original thread going to sleep and never waking up.

I was reading the libstdc++ and libc++ implementations of std::condition_variable_any and noticed this code in the libc++ implementation

{lock_guard<mutex> __lx(*__mut_);}
__cv_.notify_one();

the internal mutex is locked and then immediately unlocked before the signal operation. Doesn't this risk the problem I described above?

libstdc++ seems to have gotten this right

like image 739
Curious Avatar asked Oct 29 '17 18:10

Curious


1 Answers

The C++11 and later standards explicitly say "The execution of notify_one and notify_all shall be atomic". So in one sense I think that you are correct that the internal mutex should be held across the call down to the platform's underlying condition variable notify call (for example pthread_cond_signal())

However, I don't think that the libc++ implementation will cause notifications to be missed because without the notifying thread synchronizing on the lock the waiting thread passes to wait() (or some other synchronization between the two threads) while calling notify_one() (or notify_all()) there is no way to ensure which of the two threads is 'first' to the notify or wait anyway. So if the notification can be missed in libc++'s current implementation, it could also be missed if libc++ were changed to hold the internal lock across its call down to the platform's notify API.

So I think that libc++ can invoke the "as if" rule to say that the implementation of notify_one()/notify_any() is "atomic enough".

like image 142
Michael Burr Avatar answered Nov 11 '22 20:11

Michael Burr