I.e. it is just thin wrapper around condition_variable+mutex.
Er, no. Just because it has members of those types doesn't make it a thin wrapper. Try to understand what it actually does, not just the types of its private members. There's some quite subtle code there.
- Is it thread-safe to not protect notify_one by mutex for either condition_variable_any or condition_variable?
Yes.
In fact, calling notify_one()
with the mutex locked will cause waiting threads to wake up, attempt to lock the mutex, find it is still locked by the notifying thread, and go back to sleep until the mutex is released.
If you call notify_one()
without the mutex locked then the waking threads can run immediately.
2 Why implementation of condition_variable_any uses additional mutex?
condition_variable_any
can be used with any Lockable type, not just std:mutex
, but internally the one in libstdc++ uses a condition_variable
, which can only be used with std::mutex
, so it has an internal std::mutex
object too.
So the condition_variable_any
works with two mutexes, the external one supplied by the user and the internal one used by the implementation.
3 Why implementation of condition_variable_any::notify_one and condition_variable::notify_one differs? Maybe condition_variable::notify_one requires manual protection but condition_variable_any::notify_one doesn't? Is it libstdc++ bug?
No, it's not a bug.
The standard requires that calling wait(mx)
must atomically unlock mx
and sleep. libstdc++ uses the internal mutex to provide that guarantee of atomicity. The internal mutex must be locked to avoid missed notifications if other threads are just about to wait on the condition_variable_any
.