std :: lock_guard还是std :: scoped_lock?


Answers:


125

scoped_lock是一个严格的优越版本lock_guard用于锁定互斥所有的一次任意数量(使用相同的死锁避免算法如std::lock)。在新代码中,您只能使用scoped_lock

lock_guard仍然存在的唯一原因是兼容性。它不能被删除,因为它在当前代码中使用。此外,事实证明,不希望更改其定义(从一元更改为可变),因为这也是可观察的,因此是重大更改(但出于某种技术原因)。


8
同样,由于类模板参数的减少,您甚至不必列出可锁定的类型。
Nicol Bolas's

3
@NicolBolas:的确如此,但这也适用于lock_guard。但这肯定会使后卫类易于使用。
Kerrek SB

6
scoped_lock仅
适用

1
因为是c ++ 17,所以兼容性是其存在的一个特别好的理由。当墨水仍从该标准干燥时,我也强烈反对任何专制主义者关于“您只能使用”的主张。
Paul Childs '18

88

唯一且重要的区别是,std::scoped_lock一个可变参数构造函数使用多个互斥量。这允许以死锁的方式锁定多个互斥锁,从而避免了仿佛std::lock使用过的方式。

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

以前,你必须做一个小舞用安全的方式来锁定多个互斥std::lock为解释这个答案

范围锁的添加使其更易于使用并避免了相关错误。您可以考虑std::lock_guard弃用。单论证案例std::scoped_lock可以实现为专门化,这样您不必担心可能的性能问题。

GCC 7已经支持std::scoped_lock由此可以看出这里

有关更多信息,您可能需要阅读标准论文


9
仅10分钟后回答您自己的问题。你真的不知道吗
Walter


3
当我在委员会中提出该问题时,答案是“一无所有”。可能是某种算法的退化情况,这是正确的事情。或者,可能有足够多的人在打算锁定某物时意外地不锁定任何东西,这是一个普遍的问题。我真的不确定。
霍华德·辛南特

3
@HowardHinnant: scoped_lock lk; // locks all mutexes in scope。LGTM。
Kerrek SB

2
@KerrekSB: scoped_lock lk;是的新缩写scoped_lock<> lk;。这里没有互斥。所以你是对的。;-)
Howard Hinnant

26

答案较晚,主要是针对以下问题:

您可以考虑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在上面的两个示例中使用,则第一个示例是编译时错误,而不是运行时错误,第二个示例与使用的版本具有相同的功能scoped_lock

因此,我的建议是使用最简单的工具来完成这项工作:

  1. lock_guard 如果您需要为整个示波器精确锁定1个互斥锁。

  2. scoped_lock 如果您需要锁定多个互斥量不完全为1。

  3. unique_lock如果您需要在区块范围内解锁(包括使用condition_variable)。

这个建议 没有暗示scoped_lock要重新设计,以不接受0互斥。在有效的使用案例中,需要scoped_lock接受可变参数模板参数包(可能为空)。而空的情况下,应作任何锁定。

这就是为什么lock_guard不推荐使用。 scoped_lock 并且 unique_lock可能是的功能超集lock_guard,但事实是一把双刃剑。有时,类型将不起作用也同样重要(在这种情况下为默认构造)。


13

这是C ++ Concurrency in Action的示例和报价:

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

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意味着std::lock现在可以使用编写大多数在c ++ 17之前使用过的情况std::scoped_lock,而发生错误的可能性较小,这只是一件好事!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.