为什么逻辑 AND/OR 的左操作数不依赖于父评估?

问题描述

根据 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;

解决方法

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

这完全是关于数据依赖,而不是像条件分支这样的控制依赖。 C++11: the difference between memory_order_relaxed and memory_order_consume[[carries_dependency]] what it means and how to implement 有更多详细信息。

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

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

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

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...