我正在寻找一个 bug ,其中有些杂乱的线程/条件变量类已更新为使用C++ 11线程。在搜寻过程中,我在GCC代码库中遇到了以下内容:

  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);
  }

尽管有评论,但我很难理解这里将构造函数移到__my_lock2的目的。为什么__my_lock移到了__my_lock2?

最佳答案

这看起来不像condition_variable代码。它看起来像condition_variable_any代码。后者具有模板化的等待功能。前者没有。

N2406可能会阐明您所看到的内容。在N2406中,condition_variable_any改名为gen_cond_var,但其他类型相同。本文介绍了一种死锁情况,除非特别注意确保_M_mutex__lock以非常特定的顺序锁定和解锁,否则就会实现死锁。

尽管您显示的代码与N2406上的代码不同,但我强烈怀疑它们的构造都是为了按顺序锁定和解锁这两个锁,从而避免了N2406中描述的死锁。如果没有进一步了解_Unlock的定义,我仍然不能绝对确定。但是,一个强有力的线索是此等待函数在N2406中的最终注释:

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

IE。成员互斥锁必须先解锁,然后再锁定外部__lock。通过将__my_lock移到范围小于__unlock的局部变量中,很可能正确地排序了
}  // _M_mutex.unlock(), __lock.lock()

已经实现。要了解为什么这种排序如此重要,您必须阅读N2406的相关部分(它可以防止死锁)。

08-28 16:36