具有单个互斥锁的 std::scoped_lock 行为

std::scoped_lock behaviour with a single mutex

提问人:Fareanor 提问时间:1/29/2020 最后编辑:curiousguyFareanor 更新时间:1/30/2020 访问量:1004

问:

上下文:

我知道自从 std::lock_guardstd::scoped_lock

我也知道这是首选,因为它可以处理多个互斥锁,并以与它相同的方式使用死锁避免算法。std::scoped_lockstd::lock

我在这里感兴趣的是,我们只有一个互斥锁,因此我们不需要关心死锁的避免。

我从这个答案中读到:

您可以考虑已弃用。的单参数案例可以作为专业化来实现,因此您不必担心可能的性能问题。std::lock_guardstd::scoped_lock

问题:

我想知道这句话有多少是真的。

我的意思是,是否保证(根据标准)使用单个互斥锁,将是专用的,以便它能够消除由于死锁避免处理而导致的任何不必要的开销?std::scoped_lock


我的想法:

经过对这个问题的一番调查,我从cpreference中发现了以下句子:

如果给定多个互斥锁,则使用死锁避免算法,就好像 by .std::lock

这可以让我们推断出这样的事情不会发生(即,如果只给出一个互斥锁)。
但再一次,这只是一个假设。

从这个 c++ 草案中,我没有看到任何关于这种专业化的明确提及。
我得到的唯一一句话是:

当是时,提供的类型应满足 Cpp17BasicLockable 要求。否则,每种互斥锁类型都应满足 Cpp17Lockable 要求。sizeof...(MutexTypes)1Mutex

(强调我的)

我知道 BasicLockable 要求存在并满足此处定义的条件的功能。
另一方面,Lockable 要求假定 BasicLockable 要求,并添加了满足此处定义的条件的函数。
lock()unlock()try_lock()

我知道该函数是运行 使用的死锁避免算法所必需的。try_lock()std::lock

从上面的 草稿摘录中所述,因此,如果我们只给 一个互斥锁,则不需要该函数。
这是否足以推断/考虑上述专业化始终被定义(并且可能表现得如此)。
我会说是的,但由于我从未看到任何明确提及它,我想知道我是否是对的,或者我是否错过了什么?
try_lock()std::scoped_lockstd::lock_guard


编辑:

我只是注意到我错过了这里最重要的部分,它指出:

效果:使用 初始化。那么如果是,则没有效果。否则,如果 是 ,则 。否则,锁定 (m...)。pmtie(m...)sizeof...(MutexTypes)0sizeof...(MutexTypes)1m.lock()

(强调我的)

它回答了我的询问,只有在有多个给定的互斥锁时才会调用。在问这个问题之前,我应该先看过......std::lock

+17 C ++ 语言律师 互斥锁 scoped-lock

评论


答:

4赞 Anthony Williams 1/29/2020 #1

std::scoped_lock要求其行为与仅提供一个互斥锁时的行为相同。因此,对单个互斥锁情况的要求不同。std::lock_guard

这可以通过专业化来完成,也可以通过不同的内部机制来完成,只要行为是相同的。

评论

0赞 Fareanor 1/29/2020
感谢您的确认。实际上,我错过了最重要的部分。在问我的问题之前,我应该注意到它:)
2赞 Timo 1/29/2020 #2

如果您阅读(就在上面)的规范,应该很清楚。lock_guardscoped_lock

[线程.lock.guard]-3

使用 m 初始化 pm。 调用 m.lock()

[线程锁定作用域]-3

使用 tie(m...) 初始化 pm。[...]否则,如果 sizeof...(MutexTypes) 为 1,则为 m.lock()。[...]

它没有明确提到使用,但需要具有相同的行为。lock_guard

评论

0赞 Fareanor 1/29/2020
是的,我注意到这部分为时已晚(在我的编辑中提到)。
0赞 n314159 1/29/2020 #3

该标准很少会通过专业化来保证某种优化(值得注意的例子是对不同迭代器类型的专业化和可憎的 )。为此,有两种方法可以做到这一点:std::vector<bool>

  1. 信任您的编译器/标准库实现。编译器是史诗般的,它们可以进行极其高级的优化,其中一些是你梦寐以求的。在大多数情况下,STL 的实现都很棒。有些领域它们的速度较慢,因为它们必须能够处理奇怪的边缘情况,但这里必须已经有不同的专业化,因为一个参数案例只需要 BasicLockable,所以它将有一个不需要的实现,所以为什么它不应该是有效的。try_lock
  2. 执行代码。测试它是否足够快,测试它是否在代码的热路径上,如果你真的认为(并有数据证明)它很慢,那么然后才替换它并再次测试。scoped_lockscoped_locklock_guard

评论

0赞 Fareanor 1/29/2020
同意,但我不能依靠可能的编译器优化来发布与编译器无关的一般确定性。我唯一可以信任的保证是标准给出的保证。潜在的问题是,我想知道我是否可以完全摆脱它,并保证它不会产生任何不必要的开销,只有一个互斥锁。std::lock_guard