std :: lock_guard或std :: scoped_lock?

时间:2017-03-25 17:30:00

标签: c++ multithreading locking c++17

C ++ 17引入了一个名为std::scoped_lock的新锁类。

从文档来看,它看起来与现有的std::lock_guard类相似。

有什么区别,什么时候应该使用它?

4 个答案:

答案 0 :(得分:71)

scoped_locklock_guard的严格优越版本,可以同时锁定任意数量的互斥锁(使用与std::lock相同的死锁避免算法)。在新代码中,您应该只使用scoped_lock

lock_guard仍然存在的唯一原因是兼容性。它不能被删除,因为它在当前代码中使用。此外,事实证明,改变其定义(从一元到变量)是不可取的,因为这也是一种可观察的,因此也是破坏性的变化(但由于技术上的某些原因)。

答案 1 :(得分:47)

唯一且重要的区别是std::scoped_lock有一个可变参数构造函数,它使用多个互斥锁。这允许以死锁方式锁定多个互斥锁,就像使用std::lock一样。

{
    // safely locked as if using std::lock
    std::scoped_lock<std::mutex, std::mutex> lock(mutex1, mutex2);     
}

以前你必须按照this answer的解释使用std::lock安全地锁定多个互斥锁。

添加范围锁使这更容易使用并避免相关错误。您可以考虑弃用std::lock_guardstd::scoped_lock的单个参数案例可以作为专业化来实现,因此您不必担心可能的性能问题。

GCC 7已经支持std::scoped_lock here

有关详细信息,您可能需要阅读standard paper

答案 2 :(得分:45)

最新答案,主要是针对以下问题:

您可以考虑弃用std::lock_guard

对于通常只需要锁定一个互斥锁的常见情况,std::lock_guard的API使用起来比scoped_lock更加安全。

例如:

{
   std::scoped_lock lock;  // protect this block
   ...
}

上面的代码段可能是偶然的运行时错误,因为它会编译然后完全不执行任何操作。编码器可能意味着:

{
   std::scoped_lock lock{mut};  // protect this block
   ...
}

现在它会锁定/解锁mut

如果在以上两个示例中使用了lock_guard,则第一个示例是编译时错误而不是运行时错误,第二个示例与使用{{1 }}。

所以我的建议是使用最简单的工具来完成这项工作:

  1. scoped_lock,如果您需要在整个范围内精确锁定1个互斥锁。

  2. lock_guard,如果您需要锁定数量不完全为1的互斥体。

  3. scoped_lock,如果您需要在块范围内解锁(包括与unique_lock一起使用)。

此建议 不是暗示condition_variable应该重新设计为不接受0个互斥量。存在有效的用例,其中希望scoped_lock接受可变参数模板参数包,该参数包可能为空。空的情况下应该锁定任何内容。

这就是scoped_lock不被弃用的原因。 lock_guard scoped_lock可能是unique_lock功能的超集,但事实是一把双刃剑。有时候,不会的类型同样重要(在这种情况下为默认构造)。

答案 3 :(得分:2)

以下是 C ++并发操作中的示例和报价:

friend void swap(X& lhs, X& rhs)
{
    if (&lhs == & rhs)
        return;
    std::lock(lhs.m, rhs.m);
    std::lock_guard<std::mutex> lock_a(lhs.m, std::adopt_lock);
    std::lock_guard<std::mutex> lock_b(rhs.m, std::adopt_lock);
    swap(lhs.some_detail, rhs.some_detail);
}

vs。

friend void swap(X& lhs, X& rhs)
{
    if (&lhs == &rhs)
        return;
    std::scoped_lock guard(lhs.m, rhs.m);
    swap(lhs.some_detail, rhs.some_detail);
}
  

std::scoped_lock的存在意味着在c ++ 17之前您本可以使用std::lock的大多数情况现在都可以使用std::scoped_lock来编写,错误的可能性较小,这只能是一件好事!