C++ std::lock_guard 还是 std::scoped_lock?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43019598/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:32:31  来源:igfitidea点击:

std::lock_guard or std::scoped_lock?

c++multithreadinglockingc++17

提问by Stephan Dollberg

C++17 introduced a new lock class called std::scoped_lock.

C++17 引入了一个名为std::scoped_lock.

Judging from the documentation it looks similar to the already existing std::lock_guardclass.

从文档来看,它看起来类似于已经存在的std::lock_guard类。

What's the difference and when should I use it?

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

采纳答案by Stephan Dollberg

The single and important difference is that std::scoped_lockhas a variadic constructor taking more than one mutex. This allows to lock multiple mutexes in a deadlock avoiding way as if std::lockwere used.

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

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

Previously you had to do a little dance to lock multiple mutexes in a safe way using std::lockas explained this answer.

以前,您必须std::lock按照此答案的说明,以安全的方式锁定多个互斥锁。

The addition of scope lock makes this easier to use and avoids the related errors. You can consider std::lock_guarddeprecated. The single argument case of std::scoped_lockcan be implemented as a specialization and such you don't have to fear about possible performance issues.

范围锁的添加使其更易于使用并避免了相关错误。你可以考虑std::lock_guard弃用。的单参数情况std::scoped_lock可以作为特化来实现,这样您就不必担心可能出现的性能问题。

GCC 7 already has support for std::scoped_lockwhich can be seen here.

GCC 7 已经支持std::scoped_lock,可以在这里看到。

For more information you might want to read the standard paper

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

回答by Kerrek SB

The scoped_lockis a strictly superior version of lock_guardthat locks an arbitrary number of mutexes all at once (using the same deadlock-avoidance algorithm as std::lock). In new code, you should only ever use scoped_lock.

scoped_lock是一次lock_guard锁定任意数量的互斥锁的严格高级版本(使用与 相同的死锁避免算法std::lock)。在新代码中,您应该只使用scoped_lock.

The only reason lock_guardstill exists is for compatibility. It could not just be deleted, because it is used in current code. Moreover, it proved undesirable to change its definition (from unary to variadic), because that is also an observable, and hence breaking, change (but for somewhat technical reasons).

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

回答by Howard Hinnant

Late answer, and mostly in response to:

迟到的答案,主要是为了回应:

You can consider std::lock_guarddeprecated.

你可以考虑std::lock_guard弃用。

For the common case that one needs to lock exactly one mutex, std::lock_guardhas an API that is a little safer to use than scoped_lock.

对于需要精确锁定一个互斥锁的常见情况,std::lock_guard使用比scoped_lock.

For example:

例如:

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

The above snippet is likely an accidental run-time error because it compiles and then does absolutely nothing. The coder probably meant:

上面的代码片段很可能是一个意外的运行时错误,因为它编译后什么也没做。编码器可能的意思是:

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

Nowit locks/unlocks mut.

现在它锁定/解锁mut

If lock_guardwas used in the two examples above instead, the first example is a compile-time error instead of a run-time error, and the second example has identical functionality as the version which uses scope_lock.

如果lock_guard在上面的两个示例中使用,则第一个示例是编译时错误而不是运行时错误,第二个示例与使用scope_lock.

So my advice is to use the simplest tool for the job:

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

  1. lock_guardif you need to lock exactly 1 mutex for an entire scope.

  2. scoped_lockif you need to lock a number of mutexes that is not exactly 1.

  3. unique_lockif you need to unlock within the scope of the block (which includes use with a condition_variable).

  1. lock_guard如果您需要为整个范围恰好锁定 1 个互斥锁。

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

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

This advice doesnotimply that scoped_lockshould be redesigned to not accept 0 mutexes. There exist valid use cases where it is desirable for scoped_lockto accept variadic template parameter packs which may be empty. And the empty case should notlock anything.

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

And that's why lock_guardisn't deprecated. scoped_lockandunique_lockmay be a superset of functionality of lock_guard, but that fact is a double-edged sword. Sometimes it is just as important what a type won'tdo (default construct in this case).

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

回答by u6949852

Here is a sample and quote from C++ Concurrency in Action:

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

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

The existence of std::scoped_lockmeans that most of the cases where you would have used std::lockprior to c++17 can now be written using std::scoped_lock, with less potential for mistakes, which can only be a good thing!

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