std :: timed_mutex :: try_lock *虚假失败

时间:2015-11-25 03:27:11

标签: c++ multithreading c++11 mutex thread-synchronization

截至try_lock*,我的意思是try_lock()try_lock_for()try_lock_until()。根据{{​​3}},这三种方法可能只是虚假地失败。以下内容引自try_lock_for()

的说明
  

try_lock()一样,允许此函数虚假失败   即使互斥锁未被任何其他线程锁定,也返回false   timeout_duration期间的某个时刻。

我知道std::condition_variable及其背后的理由可能会发生虚假的唤醒。但是,互斥体的情况如何呢?

2 个答案:

答案 0 :(得分:16)

根据:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3209.htm

  

另一方面,有充分的理由要求编写程序以容忍虚假的try_lock()失败:

     
      
  1. 正如Boehm,Adve," C ++并发内存模型基础" PLDI 08所指出的那样,在没有虚假try_lock()失败的情况下强制执行无数据争用程序的顺序一致性需要更强大的内存排序对于try_lock()上的lock()操作 - 兼容的互斥锁类型。在一些架构上,显着增加了无争用互斥收购的成本。这个成本似乎大大超过了禁止虚假try_lock()失败的任何好处。
  2.   
  3. 它允许用户编写的try_lock()失败,例如,如果实现无法获取用于保护互斥锁数据结构的低级锁定。或者它允许直接用compare_exchange_weak。
  4. 编写这样的操作   
  5. 例如,当引入调试线程时,它确保客户端代码保持正确,该调试线程偶尔获取锁,以便能够从正在检查或检查的数据结构中读取一致值。从try_lock()失败中获取信息的任何代码都会因为引入另一个纯粹锁定和读取数据结构的线程而中断。
  6.   

答案 1 :(得分:6)

来自C ++ 14章" 30.4.1.2互斥体类型"

第16段:

  

即使没有任何其他线程持有,实现也可能无法获得锁定。 [注意:这种虚假失败通常不常见,但允许基于简单比较和交换的有趣实现(第29条)。 -end note]实施应确保try_lock()在没有竞争互斥收购的情况下不会始终返回false

和第19段:

  即使在没有虚假失败的情况下,也很难知道失败后的状态

回答

  

我知道std :: condition_variable可能会发生虚假唤醒   以及它背后的基本原理。但是,互斥体的情况如何呢?

std::timed_mutex有时是在操作系统中没有直接支持时使用std::condition_varible实现的。与在GNU libstdc ++中一样:

#if _GTHREAD_USE_MUTEX_TIMEDLOCK

...

#else // !_GTHREAD_USE_MUTEX_TIMEDLOCK

  class timed_mutex
  {
    mutex       _M_mut;
    condition_variable  _M_cv;
    bool        _M_locked = false;

  public:

    template<typename _Rep, typename _Period>
      bool
      try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
      {
        unique_lock<mutex> __lk(_M_mut);
        if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; }))
          return false;
        _M_locked = true;
        return true;
      }

    template<typename _Clock, typename _Duration>
      bool
      try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
      {
        unique_lock<mutex> __lk(_M_mut);
        if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; }))
          return false;
        _M_locked = true;
        return true;
      }
  };

#endif