提问人:Fareanor 提问时间:1/29/2020 最后编辑:curiousguyFareanor 更新时间:1/30/2020 访问量:1004
具有单个互斥锁的 std::scoped_lock 行为
std::scoped_lock behaviour with a single mutex
问:
上下文:
我知道自从 c++17 和 .std::lock_guard
std::scoped_lock
我也知道这是首选,因为它可以处理多个互斥锁,并以与它相同的方式使用死锁避免算法。std::scoped_lock
std::lock
我在这里感兴趣的是,我们只有一个互斥锁,因此我们不需要关心死锁的避免。
我从这个答案中读到:
您可以考虑已弃用。的单参数案例可以作为专业化来实现,因此您不必担心可能的性能问题。
std::lock_guard
std::scoped_lock
问题:
我想知道这句话有多少是真的。
我的意思是,是否保证(根据标准)使用单个互斥锁,将是专用的,以便它能够消除由于死锁避免处理而导致的任何不必要的开销?std::scoped_lock
我的想法:
经过对这个问题的一番调查,我从cpreference中发现了以下句子:
如果给定多个互斥锁,则使用死锁避免算法,就好像 by .
std::lock
这可以让我们推断出这样的事情不会发生(即,如果只给出一个互斥锁)。
但再一次,这只是一个假设。
从这个 c++ 草案中,我没有看到任何关于这种专业化的明确提及。
我得到的唯一一句话是:
当是时,提供的类型应满足 Cpp17BasicLockable 要求。否则,每种互斥锁类型都应满足 Cpp17Lockable 要求。
sizeof...(MutexTypes)
1
Mutex
(强调我的)
我知道 BasicLockable 要求存在并满足此处定义的条件的功能。
另一方面,Lockable 要求假定 BasicLockable 要求,并添加了满足此处定义的条件的函数。lock()
unlock()
try_lock()
我知道该函数是运行 使用的死锁避免算法所必需的。try_lock()
std::lock
从上面的 c++ 草稿摘录中所述,因此,如果我们只给 一个互斥锁,则不需要该函数。
这是否足以推断/考虑上述专业化始终被定义(并且可能表现得如此)。
我会说是的,但由于我从未看到任何明确提及它,我想知道我是否是对的,或者我是否错过了什么?try_lock()
std::scoped_lock
std::lock_guard
编辑:
我只是注意到我错过了这里最重要的部分,它指出:
效果:使用 初始化。那么如果是,则没有效果。否则,如果 是 ,则 。否则,
锁定 (m...)。
pm
tie(m...)
sizeof...(MutexTypes)
0
sizeof...(MutexTypes)
1
m.lock()
(强调我的)
它回答了我的询问,只有在有多个给定的互斥锁时才会调用。在问这个问题之前,我应该先看过......std::lock
答:
std::scoped_lock
要求其行为与仅提供一个互斥锁时的行为相同。因此,对单个互斥锁情况的要求不同。std::lock_guard
这可以通过专业化来完成,也可以通过不同的内部机制来完成,只要行为是相同的。
评论
如果您阅读(就在上面)的规范,应该很清楚。lock_guard
scoped_lock
使用 m 初始化 pm。 调用 m.lock()
使用 tie(m...) 初始化 pm。[...]否则,如果 sizeof...(MutexTypes) 为 1,则为 m.lock()。[...]
它没有明确提到使用,但需要具有相同的行为。lock_guard
评论
该标准很少会通过专业化来保证某种优化(值得注意的例子是对不同迭代器类型的专业化和可憎的 )。为此,有两种方法可以做到这一点:std::vector<bool>
- 信任您的编译器/标准库实现。编译器是史诗般的,它们可以进行极其高级的优化,其中一些是你梦寐以求的。在大多数情况下,STL 的实现都很棒。有些领域它们的速度较慢,因为它们必须能够处理奇怪的边缘情况,但这里必须已经有不同的专业化,因为一个参数案例只需要 BasicLockable,所以它将有一个不需要的实现,所以为什么它不应该是有效的。
try_lock
- 执行代码。测试它是否足够快,测试它是否在代码的热路径上,如果你真的认为(并有数据证明)它很慢,那么然后才替换它并再次测试。
scoped_lock
scoped_lock
lock_guard
评论
std::lock_guard
评论