[英]std::scoped_lock behaviour with a single mutex
Context:语境:
I know that std::lock_guard
became kind of deprecated since the arrival of c++17 with std::scoped_lock
.我知道自从带有
std::scoped_lock
的c++17到来以来, std::lock_guard
变得有点过时了。
I also know that std::scoped_lock
is preferred since it can handle several mutexes and uses a deadlock avoidance algorithm the same way as std::lock
does.我也知道
std::scoped_lock
是首选,因为它可以处理多个互斥体并使用与std::lock
相同的死锁避免算法。
I'm interested here in the case we have only one single mutex and thus we don't need to care about deadlock avoidance.我在这里对我们只有一个互斥锁的情况感兴趣,因此我们不需要关心避免死锁。
I have read from this answer that:我从这个答案中读到:
You can consider
std::lock_guard
deprecated.您可以考虑不推荐使用
std::lock_guard
。 The single argument case ofstd::scoped_lock
can be implemented as a specialization and such you don't have to fear about possible performance issues.std::scoped_lock
的单参数情况可以作为std::scoped_lock
来实现,这样您就不必担心可能出现的性能问题。
Question:题:
I'm wondering how much this sentence is true.我想知道这句话有多少是真的。
I mean, is it guaranteed (by the standard) that with a single mutex, std::scoped_lock
will be specialized so that it will get rid of any unnecessary overhead due to deadlock avoidance handling ?我的意思是,是否保证(根据标准)使用单个互斥锁,
std::scoped_lock
将被专门化,以便消除由于死锁避免处理而产生的任何不必要的开销?
My thoughts:我的想法:
After some investigation on the question, I found from cppreference the following sentence:经过对该问题的一些调查,我从cppreference 中找到了以下句子:
If several mutexes are given, deadlock avoidance algorithm is used as if by
std::lock
.如果给出了多个互斥体,则使用死锁避免算法,就像
std::lock
。
Which could let us deduce that such a thing would not happen otherwise (ie if only one mutex is given).这可以让我们推断出这样的事情不会发生(即如果只给出一个互斥锁)。
But once again, it is just an assumption.但再一次,这只是一个假设。
From this c++ draft I don't see any explicit mention about such a specialization.从这个c++ 草案中,我没有看到任何关于这种专业化的明确提及。
The only sentence I got is:我得到的唯一一句话是:
When
sizeof...(MutexTypes)
is1
, the suppliedMutex
type shall meet the Cpp17BasicLockable requirements.当
sizeof...(MutexTypes)
为1
,提供的Mutex
类型应满足Cpp17BasicLockable要求。 Otherwise, each of the mutex types shall meet the Cpp17Lockable requirements.否则,每个互斥类型都应满足Cpp17Lockable要求。
(emphasis mine) (强调我的)
I know that the BasicLockable requirements mandate the existence of lock()
and unlock()
functions which meet the conditions such as defined here .我知道BasicLockable要求要求存在满足此处定义的条件的
lock()
和unlock()
函数。
On the other hand, the Lockable requirements assume the BasicLockable requirements with the addition of a try_lock()
function which meet the conditions such as defined there .在另一方面中,可锁定要求假设与加入的BasicLockable要求
try_lock()
其满足条件,如定义的函数那里。
I know that the try_lock()
function is required in order to run the deadlock avoidance algorithm used by std::lock
.我知道需要
try_lock()
函数才能运行std::lock
使用的死锁避免算法。
From what's stated in the above c++ draft extract, the try_lock()
function is thus not required if we give only one mutex to std::scoped_lock
.根据上述c++草案摘录中所述,如果我们只给
std::scoped_lock
一个互斥锁,则不需要try_lock()
函数。
Is this sufficient to deduce/consider that the above specialization is always defined (and presumably behaves as std::lock_guard
would do).这是否足以推断/考虑始终定义上述专业化(并且可能表现得像
std::lock_guard
会做的那样)。
I would say yes but as I never saw any explicit mention about it, I wonder if I'm right or if I missed something ?我会说是的,但因为我从未看到任何明确提及它,我想知道我是对的还是我错过了什么?
EDIT:编辑:
I just noticed that I missed the most important part here which states:我只是注意到我错过了这里最重要的部分,它指出:
Effects : Initializes
pm
withtie(m...)
.效果:用
tie(m...)
初始化pm
。 Then ifsizeof...(MutexTypes)
is0
, no effects.然后,如果
sizeof...(MutexTypes)
为0
,则没有效果。 Otherwise ifsizeof...(MutexTypes)
is1
, thenm.lock()
.否则,如果
sizeof...(MutexTypes)
为1
,则m.lock()
。 Otherwise,lock(m...)
.否则,
lock(m...)
。
(emphasis mine) (强调我的)
Which answers my interrogations, std::lock
is called only when there is more than one given mutex.这回答了我的询问,只有在有多个给定的互斥
std::lock
才会调用std::lock
。 I should have seen it before asking the question...在问这个问题之前我应该看到它...
std::scoped_lock
is required to behave identically to std::lock_guard
when only one mutex is supplied.当仅提供一个互斥锁时,要求
std::scoped_lock
行为与std::lock_guard
相同。 Hence the different requirement for the single mutex case.因此对单个互斥体的情况有不同的要求。
This could be done with a specialization, or it could be done via a different internal mechanism, as long as the behaviour is the same.这可以通过专门化来完成,也可以通过不同的内部机制来完成,只要行为是相同的。
If you read the specification of lock_guard
(which is right above scoped_lock
) it should be clear.如果您阅读了
lock_guard
的规范(就在scoped_lock
),那应该很清楚。
[thread.lock.guard]-3 [thread.lock.guard]-3
Initializes pm with m.
用 m 初始化 pm。 Calls m.lock()
调用 m.lock()
[thread.lock.scoped]-3 [thread.lock.scoped]-3
Initializes pm with tie(m...).
用 tie(m...) 初始化 pm。 [...] Otherwise if sizeof...(MutexTypes) is 1, then m.lock().
[...] 否则如果 sizeof...(MutexTypes) 为 1,则 m.lock()。 [...]
[...]
It doesn't explicitly mention to use lock_guard
but it is required to have the same behavior.它没有明确提到使用
lock_guard
但需要具有相同的行为。
The standard will seldomly guarantee some kind of optimization though specialization (Notable examples are specializations on different iterator typea and the abomination which is std::vector<bool>
).该标准很少通过专业化来保证某种优化(值得注意的例子是对不同迭代器类型的专业化和
std::vector<bool>
可恶之处)。 For this there are two ways to go at it:为此,有两种方法:
try_lock
, so why shouldn't it be efficient.try_lock
,那么为什么它不应该是有效的。scoped_lock
is on a hot path of your code and if you really think (and have data to prove it) that scoped_lock
is slow, then and only then replace it with lock_guard
and test again.scoped_lock
是否在你的代码的热门路径上,如果你真的认为(并有数据证明) scoped_lock
很慢,那么然后才用lock_guard
替换它并再次测试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.