The function (which I believe to be std::condition_variable_any<_Lock>::wait
) is avoiding deadlock by establishing a lock ordering invariant that __lock
must be locked before acquiring _M_mutex
. While doing so, it must somehow still guarantee that __lock
is not held while waiting on the internal condition variable _M_cond
. Note that _Unlock<_Lock>
is an RAII unlocking object. It performs the opposite function of the usual lock guards by unlocking in its constructor and locking in the destructor. The necessary ordering of events is:
- acquire
__lock
(pre-condition of thewait
call) - acquire
_M_mutex
(in the__my_lock
constructor) - release
__lock
(in the__unlock
constructor) - atomically release
_M_mutex
and wait on_M_cond
(happens in_M_cond.wait
) - reacquire
_M_mutex
on wakeup (also in_M_cond.wait
) - release
_M_mutex
(in the__my_lock2
destructor) - reacquire
__lock
(in the__unlock
destructor)
The move from __my_lock
to __my_lock2
is necessary so that __my_lock2
will be destroyed before __unlock
ensuring that event 6 happens before 7 instead of after.