Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC C++11 Condition Variable Wait Internals

I'm hunting down a bug we have with some messy thread/condition variable classes being updated to use C++11 threads. During the course of the hunt, I've come across the following in the GCC codebase:

  template<typename _Lock>
  void
  wait(_Lock& __lock)
  {
    unique_lock<mutex> __my_lock(_M_mutex);
    _Unlock<_Lock> __unlock(__lock);
    // _M_mutex must be unlocked before re-locking __lock so move
    // ownership of _M_mutex lock to an object with shorter lifetime.
    unique_lock<mutex> __my_lock2(std::move(__my_lock));
    _M_cond.wait(__my_lock2);
  }

Despite the comment, I'm having difficulty understanding the purpose of the move constructor here to __my_lock2. Why is __my_lock moved to __my_lock2 here?

like image 864
Andy Avatar asked Dec 09 '22 09:12

Andy


1 Answers

This does not look like condition_variable code. It looks like condition_variable_any code. The latter has a templated wait function. The former does not.

N2406 may shed light on what you are seeing. In N2406, condition_variable_any is instead named gen_cond_var, but otherwise, the types are identical. This paper describes a deadlock scenario whereupon deadlock is achieved unless great care is taken to assure that _M_mutex and __lock are locked and unlocked in a very specific order.

While the code you show, and the code at N2406, is not the same, I strongly suspect that they are both built to lock and unlock these two locks in an order so as to avoid the deadlock described in N2406. Without further insight into the definition of _Unlock, I can not be absolutely certain though. However a strong clue is the final comment in N2406 of the this wait function:

}  // mut_.unlock(), external.lock()

I.e. the member mutex must be unlocked prior to locking the external __lock. By moving __my_lock to a local variable with scope less than that of __unlock, it is highly likely that the correct ordering of

}  // _M_mutex.unlock(), __lock.lock()

has been achieved. To understand why this ordering is so critically important, you have to read the associated section of N2406 (it prevents deadlock).

like image 184
Howard Hinnant Avatar answered Dec 11 '22 00:12

Howard Hinnant