gpt4 book ai didi

c++ - 理解 C++11 中的 std::atomic::compare_exchange_weak()

转载 作者:IT老高 更新时间:2023-10-28 12:05:23 44 4
gpt4 key购买 nike

bool compare_exchange_weak (T& expected, T val, ..);
compare_exchange_weak()是 C++11 中提供的比较交换原语之一。它是 从某种意义上说,即使对象的值等于 expected,它也会返回 false。 .这是由于 虚假故障 在一些使用一系列指令(而不是 x86 上的指令)来实现它的平台上。在这样的平台上,上下文切换、另一个线程重新加载相同地址(或缓存行)等可能会使原语失败。它是 spurious因为它不是操作失败的对象的值(不等于 expected )。相反,这是一种时间问题。
但令我困惑的是 C++11 标准 (ISO/IEC 14882) 中所说的,

29.6.5..A consequence of spurious failure is that nearly all uses of weakcompare-and-exchange will be in a loop.


为什么它必须在 中循环几乎所有用途 ?这是否意味着当它因为虚假故障而失败时我们将循环?如果是这样,我们为什么还要使用 compare_exchange_weak()并自己编写循环?我们可以使用 compare_exchange_strong()我认为这应该为我们摆脱虚假的失败。 compare_exchange_weak()的常见用例有哪些?
另一个问题相关。 Anthony 在他的《C++ Concurrency In Action》一书中说,
//Because compare_exchange_weak() can fail spuriously, it must typically
//be used in a loop:

bool expected=false;
extern atomic<bool> b; // set somewhere else
while(!b.compare_exchange_weak(expected,true) && !expected);

//In this case, you keep looping as long as expected is still false,
//indicating that the compare_exchange_weak() call failed spuriously.
为什么是 !expected有在循环条件?是否可以防止所有线程可能会饿死并且在一段时间内没有任何进展?
最后一个问题
在不存在单个硬件 CAS 指令的平台上,弱版本和强版本都是使用 LL/SC 实现的(如 ARM、PowerPC 等)。那么以下两个循环之间有什么区别吗?为什么,如果有? (对我来说,它们应该具有相似的性能。)
// use LL/SC (or CAS on x86) and ignore/loop on spurious failures
while (!compare_exchange_weak(..))
{ .. }

// use LL/SC (or CAS on x86) and ignore/loop on spurious failures
while (!compare_exchange_strong(..))
{ .. }
我提出了最后一个问题,你们都提到循环内可能存在性能差异。 C++11 标准 (ISO/IEC 14882) 也提到了这一点:

When a compare-and-exchange is in a loop, the weak version will yieldbetter performance on some platforms.


但如上所述,循环中的两个版本应该提供相同/相似的性能。我想念的是什么?

最佳答案

为什么要循环交换?
通常,您希望在继续之前完成您的工作,因此,您输入 compare_exchange_weak进入一个循环,以便它尝试交换直到成功(即返回 true )。
请注意,还有 compare_exchange_strong经常在循环中使用。它不会因虚假故障而失败,但会因并发写入而失败。
为什么要使用 weak而不是 strong ?
很简单:虚假故障不会经常发生,因此不会对性能造成太大影响。相比之下,容忍这种失败可以更有效地实现 weak某些平台上的版本(与 strong 相比):strong必须始终检查虚假故障并将其屏蔽。这是昂贵的。
因此,weak使用它是因为它比 strong 快很多在某些平台上
什么时候应该使用 weakstrong ?
reference状态提示何时使用 weak以及何时使用 strong :

When a compare-and-exchange is in a loop, the weak version will yieldbetter performance on some platforms. When a weak compare-and-exchangewould require a loop and a strong one would not, the strong one ispreferable.


因此,答案似乎很容易记住:如果您只因虚假故障而不得不引入循环,请不要这样做;使用 strong .如果你有一个循环,那么使用 weak .
为什么是 !expected在示例中
这取决于情况及其所需的语义,但通常不需要它的正确性。省略它会产生非常相似的语义。仅在另一个线程可能会将值重置为 false 的情况下,语义可能会略有不同(但我找不到你想要的有意义的例子)。见 Tony D.'s comment的详细解释。
当另一个线程写入 true 时,它只是一个快速 channel : 然后我们中止而不是尝试写 true再次。
关于你的最后一个问题

But as analyzed above, two versions in a loop should give the same/similar performance.What's the thing I miss?


来自 Wikipedia :

Real implementations of LL/SC do not always succeed if there are noconcurrent updates to the memory location in question. Any exceptionalevents between the two operations, such as a context switch, anotherload-link, or even (on many platforms) another load or storeoperation, will cause the store-conditional to spuriously fail. Olderimplementations will fail if there are any updates broadcast over thememory bus.


因此,例如,LL/SC 将在上下文切换时虚假失败。现在,强版本将带来它自己的“小循环”来检测虚假故障并通过重试来掩盖它。请注意,这个自己的循环也比通常的 CAS 循环更复杂,因为它必须区分虚假故障(并屏蔽它)和由于并发访问导致的故障(导致返回值 false)。弱版本没有这样自己的循环。
由于您在两个示例中都提供了显式循环,因此对于强版本,根本没有必要使用小循环。因此,在带有 strong 的示例中版本,失败检查进行了两次;一次来自 compare_exchange_strong (这更复杂,因为它必须区分虚假故障和并发访问)和一次由您的循环。这项昂贵的检查是不必要的,这也是 weak 的原因这里会更快。
另请注意,您的论点 (LL/SC) 只是 实现这一点的可能性。有更多的平台甚至有不同的指令集。此外(更重要的是),请注意 std::atomic必须支持所有可能的数据类型的所有操作,所以即使你声明了一个千万字节的结构体,你也可以使用 compare_exchange在这一点上。即使在具有 CAS 的 CPU 上,您也不能 CAS 一千万字节,因此编译器会生成其他指令(可能是锁获取,然后是非原子比较和交换,然后是锁释放)。现在,想想在交换一千万字节时会发生多少事情。因此,虽然对于 8 字节交换而言,虚假错误可能非常罕见,但在这种情况下可能更常见。
因此,简而言之,C++ 为您提供了两种语义,一种是“尽力而为”( weak ),另一种是“无论中间可能发生多少坏事,我都会这样做”( strong )。如何在各种数据类型和平台上实现这些是一个完全不同的话题。不要将您的心智模型与特定平台上的实现联系起来;标准库旨在处理比您可能意识到的更多的体系结构。我们可以得出的唯一一般结论是,保证成功通常比仅仅尝试并为可能的失败留出空间更困难(因此可能需要额外的工作)。

关于c++ - 理解 C++11 中的 std::atomic::compare_exchange_weak(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25199838/

44 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com