简体   繁体   English

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

[英]std::scoped_lock behaviour with a single mutex

Context:语境:

I know that std::lock_guard became kind of deprecated since the arrival of with std::scoped_lock .我知道自从带有std::scoped_lock到来以来, 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 of std::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) is 1 , the supplied Mutex 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 draft extract, the try_lock() function is thus not required if we give only one mutex to std::scoped_lock .根据上述草案摘录中所述,如果我们只给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 with tie(m...) .效果:用tie(m...)初始化pm Then if sizeof...(MutexTypes) is 0 , no effects.然后,如果sizeof...(MutexTypes)0 ,则没有效果。 Otherwise if sizeof...(MutexTypes) is 1 , then m.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:为此,有两种方法:

  1. Trust your compiler/standard library implementation.相信您的编译器/标准库实现。 Compilers are epic, they do extremely advanced kinds of optimization, some of them you can only dream of.编译器是史诗般的,它们进行了极其先进的优化,其中一些是您梦寐以求的。 The implementations of the STL are in most cases fantastic. STL 的实现在大多数情况下都很棒。 There are areas where they are slower since they have to be able to handle weird edge cases, but here there has to be a different specialization already since only BasicLockable is required for the one argument case, so it will have an implementation that does not need try_lock , so why shouldn't it be efficient.有些地方它们较慢,因为它们必须能够处理奇怪的边缘情况,但这里必须有一个不同的专业化,因为只需要 BasicLockable 用于一个参数情况,所以它将有一个不需要的实现try_lock ,那么为什么它不应该是有效的。
  2. Perform your code.执行你的代码。 Test if it is fast enough, test if 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM