std::scoped_lock 单个互斥锁的行为
std::scoped_lock behaviour with a single mutex
上下文:
我知道自从 c++17 与 std::scoped_lock
一起出现后,std::lock_guard
有点被弃用了。
我也知道 std::scoped_lock
是首选,因为它可以处理多个互斥锁并使用与 std::lock
相同的死锁避免算法。
我对只有一个互斥锁的情况感兴趣,因此我们不需要关心死锁避免。
我从 那里读到:
You can consider std::lock_guard
deprecated. 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
将被专门化,以便它可以消除由于死锁避免处理而导致的任何不必要的开销?
我的想法:
经过对问题的一些调查,我从cppreference中找到了以下句子:
If several mutexes are given, deadlock avoidance algorithm is used as if by std::lock
.
这可以让我们推断出这样的事情不会发生,否则(即如果只给出一个互斥量)。
但再次重申,这只是一个假设。
从这个 c++ draft 我没有看到任何关于这种专业化的明确提及。
我得到的唯一一句话是:
When sizeof...(MutexTypes)
is 1
, the supplied Mutex
type shall meet the Cpp17BasicLockable requirements. Otherwise, each of the mutex types shall meet the Cpp17Lockable requirements.
(强调我的)
我知道 BasicLockable 要求强制存在 lock()
和 unlock()
函数,这些函数满足定义的 here 等条件。
另一方面,Lockable 要求假设 BasicLockable 要求加上 try_lock()
满足定义等条件的功能there.
我知道 try_lock()
函数是 运行 std::lock
使用的死锁避免算法所必需的。
根据上述 c++ 摘录草案所述,如果我们只给 std::scoped_lock
.
一个互斥锁,则不需要 try_lock()
函数
这足以 deduce/consider 始终定义上述专业化(并且可能表现得像 std::lock_guard
会做的那样)。
我会说是的,但因为我从未看到任何明确提及它,我想知道我是否正确或者我是否遗漏了什么?
编辑:
我刚刚注意到我错过了最重要的部分 here,其中指出:
Effects: Initializes pm
with tie(m...)
. Then if sizeof...(MutexTypes)
is 0
, no effects. Otherwise if sizeof...(MutexTypes)
is 1
, then m.lock()
. Otherwise, lock(m...)
.
(强调我的)
这回答了我的疑问,std::lock
仅在存在多个给定互斥体时才被调用。我应该在问问题之前看到它...
当只提供一个互斥量时,std::scoped_lock
的行为必须与 std::lock_guard
相同。因此,对单个互斥情况的不同要求。
这可以通过专门化来完成,也可以通过不同的内部机制来完成,只要行为相同即可。
如果你读过 lock_guard
的规范(就在 scoped_lock
的正上方)应该就清楚了。
Initializes pm with m. Calls m.lock()
Initializes pm with tie(m...). [...] Otherwise if sizeof...(MutexTypes) is 1, then m.lock(). [...]
它没有明确提到使用 lock_guard
但它必须具有相同的行为。
该标准很少会通过专门化来保证某种优化(著名的例子是对不同迭代器类型 a 的专门化和可憎的 std::vector<bool>
)。为此,有两种方法可以解决:
- 相信您的 compiler/standard 库实现。编译器是史诗般的,它们进行极其高级的优化,其中一些是您梦寐以求的。 STL 的实现在大多数情况下都很棒。有些地方它们速度较慢,因为它们必须能够处理奇怪的边缘情况,但这里必须已经有不同的专业化,因为单参数情况只需要 BasicLockable,所以它将有一个不需要的实现
try_lock
,为什么不应该是高效的。
- 执行你的代码。测试它是否足够快,测试
scoped_lock
是否在你代码的热路径上,如果你真的认为(并且有数据证明)scoped_lock
很慢,然后才替换它使用 lock_guard
并再次测试。
上下文:
我知道自从 c++17 与 std::scoped_lock
一起出现后,std::lock_guard
有点被弃用了。
我也知道 std::scoped_lock
是首选,因为它可以处理多个互斥锁并使用与 std::lock
相同的死锁避免算法。
我对只有一个互斥锁的情况感兴趣,因此我们不需要关心死锁避免。
我从
You can consider
std::lock_guard
deprecated. 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
将被专门化,以便它可以消除由于死锁避免处理而导致的任何不必要的开销?
我的想法:
经过对问题的一些调查,我从cppreference中找到了以下句子:
If several mutexes are given, deadlock avoidance algorithm is used as if by
std::lock
.
这可以让我们推断出这样的事情不会发生,否则(即如果只给出一个互斥量)。
但再次重申,这只是一个假设。
从这个 c++ draft 我没有看到任何关于这种专业化的明确提及。
我得到的唯一一句话是:
When
sizeof...(MutexTypes)
is1
, the suppliedMutex
type shall meet the Cpp17BasicLockable requirements. Otherwise, each of the mutex types shall meet the Cpp17Lockable requirements.
(强调我的)
我知道 BasicLockable 要求强制存在 lock()
和 unlock()
函数,这些函数满足定义的 here 等条件。
另一方面,Lockable 要求假设 BasicLockable 要求加上 try_lock()
满足定义等条件的功能there.
我知道 try_lock()
函数是 运行 std::lock
使用的死锁避免算法所必需的。
根据上述 c++ 摘录草案所述,如果我们只给 std::scoped_lock
.
一个互斥锁,则不需要 try_lock()
函数
这足以 deduce/consider 始终定义上述专业化(并且可能表现得像 std::lock_guard
会做的那样)。
我会说是的,但因为我从未看到任何明确提及它,我想知道我是否正确或者我是否遗漏了什么?
编辑:
我刚刚注意到我错过了最重要的部分 here,其中指出:
Effects: Initializes
pm
withtie(m...)
. Then ifsizeof...(MutexTypes)
is0
, no effects. Otherwise ifsizeof...(MutexTypes)
is1
, thenm.lock()
. Otherwise,lock(m...)
.
(强调我的)
这回答了我的疑问,std::lock
仅在存在多个给定互斥体时才被调用。我应该在问问题之前看到它...
std::scoped_lock
的行为必须与 std::lock_guard
相同。因此,对单个互斥情况的不同要求。
这可以通过专门化来完成,也可以通过不同的内部机制来完成,只要行为相同即可。
如果你读过 lock_guard
的规范(就在 scoped_lock
的正上方)应该就清楚了。
Initializes pm with m. Calls m.lock()
Initializes pm with tie(m...). [...] Otherwise if sizeof...(MutexTypes) is 1, then m.lock(). [...]
它没有明确提到使用 lock_guard
但它必须具有相同的行为。
该标准很少会通过专门化来保证某种优化(著名的例子是对不同迭代器类型 a 的专门化和可憎的 std::vector<bool>
)。为此,有两种方法可以解决:
- 相信您的 compiler/standard 库实现。编译器是史诗般的,它们进行极其高级的优化,其中一些是您梦寐以求的。 STL 的实现在大多数情况下都很棒。有些地方它们速度较慢,因为它们必须能够处理奇怪的边缘情况,但这里必须已经有不同的专业化,因为单参数情况只需要 BasicLockable,所以它将有一个不需要的实现
try_lock
,为什么不应该是高效的。 - 执行你的代码。测试它是否足够快,测试
scoped_lock
是否在你代码的热路径上,如果你真的认为(并且有数据证明)scoped_lock
很慢,然后才替换它使用lock_guard
并再次测试。