是否有任何惯用的显式使用mutex :: lock()或unlock()?

时间:2014-04-04 21:11:38

标签: c++ multithreading c++11 locking mutex

使用mutex锁定关键代码区域的推荐方法是通过RAII,即

mutex_type mutex;
{ // start of critical region
  std::lock_guard<mutex_type> lock(mutex);   // first statement in critical region
  // ... do critical stuff, may throw an exception
} // end of critical region

这样当在关键区域内抛出异常时,互斥锁仍将被解锁(由std::lock_guard的析构函数)。但是,通过这种方式,成员mutex::lock()mutex::unlock()永远不会被用户代码显式调用。

mutex::lock()的主要惯用词是什么?

我问,否则让mutex::lock()公共成员宣传不良代码(避免std::lock_guard)会毫无意义。

修改 由于std::lock_guard<>std::mutex都在同一标头中定义,因此std::mutex可以很容易地与std::lock_guard<std::mutex成为朋友并保护其lock()unlock()方法:

class mutex      // use only with lock_guard<mutex>
{
  friend class lock_guard<mutex>;         // support acquire-release semantic via RAII
  friend class scoped_lock_guard<mutex>;  // for supporting more complicated semantic,
                                          //     possibly remembering the mutex state.
  // ...
protected:
  void lock();
  bool try_lock();
  void unlock();       
};

class raw_mutex  // use if you absolutely must explicitly lock, try_lock, or unlock
: public mutex
{
public:
  using mutex::lock;
  using mutex::try_lock;
  using mutex::unlock;
};

回答我的问题的一个论点就是使用mutex::lock()的唯一例外安全方法是通过RAII。因此,唯一合理的显式使用必须仅涉及noexcept(或lock)和try_lock的调用之间的unlock方法。但是,由于noexcept仅仅是暗示性的,并且没有任何承诺,因此这种使用是不安全的。 Q 正确吗?

2 个答案:

答案 0 :(得分:4)

lock_guard不是唯一需要在lock上致电unlock / mutex的人。 unique_locklocktry_lockcondition_variable_any都必须处理互斥锁。这只是标准类型。在这种情况下,友谊引入了紧密耦合,成为一种障碍。

答案 1 :(得分:1)

当存在可以绑定资源生命周期的静态作用域时,可以(并且应该)使用RAII,即在输入作用域时应该初始化资源,并在退出作用域时释放。

但是,有些情况下,没有这样的静态范围。 为了说明这一点,请将变量视为资源。当存在我们可以绑定它们的静态范围时,我们使用自动变量,但偶尔我们需要动态变量来控制它们何时被创建和销毁。

当我们使用mutex es进行互斥时,也会发生同样的情况。考虑这个任务:

您的程序控制两个资源,它必须读取并执行一系列命令。可能的命令是:

  • 锁定资源#1:1>
  • 锁定资源#2:2>
  • 解锁资源#1:1<
  • 解锁资源#2:2<
  • x写入资源#1:1x
  • x写入资源#2:2x

您的程序可以预期输入1> 1a 2> 2b 1c 1< 2d 2<, 如果程序服从命令(范围必须部分重叠),则无法使用RAII的静态范围。 所以我认为这说明了当需要显式锁定/解锁时的一种情况。


至少有一种可能的情况来自于互斥不是唯一可以使用mutex的情况:它也可以用于同步。

考虑两个并行流程PQ,每个流程在其代码中都有一个指定点。我们要求Q无法通过指定点,直到P到达自己的位置。使用mutex初始化为locked州并在lock()的指定点和Q之后立即执行unlock()操作,即可满足此要求P的指定点。可以很容易地验证此设置可以解决问题。

此处lock()放在一个进程中,而unlock()放在另一个进程中,显然没有静态范围可以包含它们,所以我们需要两个都可以独立访问。

相关问题