0

std::condition_variable works only with std::unique_lock<std::mutex>, which allows for maximal efficiency on some platforms. std::condition_variable_any provides a condition variable that works with any BasicLockable object, such as std::shared_lock.

It's confusing.

3
  • 2
    What's the confusion? std::condition_variable works only with std::unique_lock, while std::condition_variable_any works with anything that is BasicLocable, i.e. has lock() and unlock(). std::scoped_lock is not BasicLocable so it can't be used by either of the two. Commented Jun 11, 2024 at 3:19
  • 1
    Doesn't answer your question, but it related general info: here's an article I wrote on my personal website on C++ Mutexes, Concurrency, and Locks. I go over usage of std::condition_variable. Commented Jun 11, 2024 at 5:20
  • Because std::lock_guard does not have lock/unlock calls... Commented Jun 11, 2024 at 8:18

1 Answer 1

4

Why std::condition_variable is specced to only work with std::unique_lock<std::mutex>? Because it "allows for maximal efficiency on some platforms", like the docs say.

That way, condition_variable implementation can use its internal knowledge on stdlibrary implementation of unique_lock and mutex to perform the most efficient way of performing its function. E.g. libstdc++'s implementation contains this nugget:

pthread_cond_clockwait(&_M_cond,
 __lock.mutex()->native_handle(), //< go right into guts of that unique_lock AND mutex
CLOCK_MONOTONIC, &__ts);

MSVC's STL:

_Cnd_wait(_Mycnd(), _Lck.mutex()->_Mymtx());

and then to SleepConditionVariableSRW.

In both cases, there is an effective native platform way to perform a wait on platform's native condition_variable counterpart, but it requires also a native mutex handle. So in order to use it, the implementation needs not only full access to the CV, but also to the mutex. This can only be done if the outer types are all internal to the implementation.

std::condition_variable_any has no such luxury, and it cannot directly access the mutex it is given. It has to adapt somehow. Usually that means it has its own internal mutex, and it has to perform sort of lock/unlock dance between its internal mutex and external mutex locker, in order to safely "adopt" lock invariant into its mutex, then use its internal mutex to do the job, and then to do another two-mutex lock/unlock dance to "give back" lock to the external mutex. condition_variable_any can do its job with any external mutex/locker it is given (even if that external mutex cannot be used by the platform's native CV primitives), but it does it at the expense of doing a whole lot of extra work and potentially worse scalability.

Sign up to request clarification or add additional context in comments.

1 Comment

Also closely related answer: stackoverflow.com/questions/8758353/…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.