gpt4 book ai didi

c++ - cppreference 中对宽松排序的解释是错误的吗?

转载 作者:行者123 更新时间:2023-12-01 09:26:29 24 4
gpt4 key购买 nike

documentation of std::memory_order on cppreference.com有一个轻松排序的例子:

Relaxed ordering

Atomic operations tagged memory_order_relaxed are not synchronization operations; they do not impose an order among concurrent memory accesses. They only guarantee atomicity and modification order consistency.

For example, with x and y initially zero,

// Thread 1:
r1 = y.load(std::memory_order_relaxed); // A
x.store(r1, std::memory_order_relaxed); // B
// Thread 2:
r2 = x.load(std::memory_order_relaxed); // C
y.store(42, std::memory_order_relaxed); // D

is allowed to produce r1 == r2 == 42 because, although A is sequenced-before B within thread 1 and C is sequenced before D within thread 2, nothing prevents D from appearing before A in the modification order of y, and B from appearing before C in the modification order of x. The side-effect of D on y could be visible to the load A in thread 1 while the side effect of B on x could be visible to the load C in thread 2. In particular, this may occur if D is completed before C in thread 2, either due to compiler reordering or at runtime.


它说“C 在线程 2 中排在 D 之前”。
根据sequential-before的定义,可以在 Order of evaluation中找到, 如果 A 在 B 之前排序,则 A 的评估将在 B 的评估开始之前完成。由于线程 2 中 C 在 D 之前被排序,因此 C 必须在 D 开始之前完成,因此快照最后一句的条件部分将永远不会满足。

最佳答案

我相信 cppreference 是正确的。我认为这归结为“好像”规则[intro.execution]/1 .编译器只能重现由您的代码描述的程序的可观察行为。从执行这些评估的线程的角度来看,仅在评估之间建立先序关系[intro.execution]/15 .这意味着当两个连续的求值出现在某个线程的某处时,实际在该线程中运行的代码必须表现得好像第一个求值所做的任何事情确实影响了第二个求值所做的任何事情。例如

int x = 0;
x = 42;
std::cout << x;

必须打印 42。但是,编译器实际上不必将值 42 存储到对象 x 中。在从该对象读回值以打印它之前。不妨记住最后一个值要存储在 x 中。是 42 然后在将值 42 实际存储到 x 之前直接打印值 42 .事实上,如果 x是一个局部变量,它也可能只是跟踪该变量在任何时候最后分配的值,甚至从不创建对象或实际存储值 42。线程无法区分。行为总是好像有一个变量,并且好像值 42 实际存储在一个对象中 x在从该对象加载之前。但这并不意味着生成的机器代码必须在任何地方实际存储和加载任何内容。所需要的只是生成的机器代码的可观察行为与如果所有这些事情真的发生时的行为是无法区分的。

如果我们看

r2 = x.load(std::memory_order_relaxed); // C
y.store(42, std::memory_order_relaxed); // D

那么是的,C 在 D 之前被排序。但是当孤立地从这个线程来看时,C 所做的任何事情都不会影响 D 的结果。而且 D 所做的任何事情都不会改变 C 的结果。一个可以影响另一个的唯一方法是作为另一个线程中发生的事情的间接结果。但是,通过指定 std::memory_order_relaxed ,您明确声明另一个线程观察加载和存储的顺序无关紧要。由于没有其他线程可以按任何特定顺序观察加载和存储,因此其他线程无法使 C 和 D 以一致的方式相互影响。因此,实际执行加载和存储的顺序无关紧要。因此,编译器可以自由地对它们重新排序。而且,正如在该示例下面的解释中所提到的,如果在从 C 加载之前执行了来自 D 的存储,那么 r1 == r2 == 42 确实可以发生......

关于c++ - cppreference 中对宽松排序的解释是错误的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59696381/

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