1

根据 C++ 标准:

如果 - 将 A 的值用作 B 的操作数,则评估 A 对评估 B 具有依赖性,除非:

— B 是对 std::kill_dependency (29.3) 的任何特化的调用,或

— A 是内置逻辑 AND(&&,参见 5.14)或逻辑 OR(||,参见 5.15)运算符的左操作数,或

— A 是条件 (?:, 见 5.16) 运算符的左操作数,或

— A 是内置逗号 (,) 运算符 (5.18) 的左操作数;(...)

我可以理解为什么在关系之前排序的依赖会在 kill_dependency 调用时停止,但是为什么逻辑 AND、OR、逗号等运算符也会破坏依赖链?

这是否意味着下面的代码具有未定义的行为?

//thread1
int y = 2
atomicVal.store(true);

//thread2 
auto x = atomicVal.load(std::memory_order_consume);
cout << x && y;
4

1 回答 1

3

memory_order_consume试图公开用于 C++ 的 asm 级 CPU 功能。(它暂时被弃用,直到它可以被重新设计为编译器可以在实践中实现的东西,并且在源代码中不需要太多kill_dependency噪音)。理解 CPU 行为是理解旨在公开它的 C++ 东西的设计的关键。

这都是关于数据依赖关系,而不是像条件分支这样的控制依赖关系。 C++11: memory_order_relaxed 和 memory_order_consume 的区别以及[[carries_dependency]] 是什么意思以及如何实现有更多细节。

例如,一条add x2, x2, x3指令在它的两个输入寄存器都准备好之前不能执行,并且ldr w1, [x2]在地址准备好之前都不能执行加载,所以如果x2来自另一个加载,它会自动排序在这个之前。(假设 CPU 硬件设计为不违反因果关系,例如通过进行价值预测或 DEC Alpha 在极少数情况下违反因果关系的任何事情)。但可以预测,因此仅等待产生 w1 的负载是cbz w1, reg_was_zero不够的。reg_was_zero: ldr w3, [x4](这是 AArch64 asm,顺便说一句,一种保证依赖排序的弱排序 ISA。)

||or的短路评估在left && right逻辑上与 a 相同if(left) right,因此即使左侧尚未执行,也可以预期分支预测 + 推测执行会在右侧运行。 没有数据依赖,只有控制依赖。

显然,逗号left, right根本不会在双方之间建立任何联系,它基本上是一种left; right;塞进单个表达式的方式。

当然,如果你在左右两边都使用相同的变量,数据依赖可以这样存在,但它不是由操作员创建的。

于 2021-04-06T06:03:00.783 回答