英特尔指令重新排序

Instruction reordering on intel

我试图通过以下简单示例来理解指令重新排序:

int a;
int b;

void foo(){
   a = 1;
   b = 1;
}

void bar(){
   while(b == 0) continue;
   assert(a == 1);
}

众所周知,在这个例子中,如果一个线程执行foo,而另一个线程执行bar,断言可能会失败。但我不明白为什么。我查阅了Intel manual Vol. 3A, 8.2.2,发现如下:

Writes to memory are not reordered with other writes, with the following exceptions:

— streaming stores (writes) executed with the non-temporal move instructions (MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS, and MOVNTPD); and

— string operations (see Section 8.2.4.1).

这里没有字符串操作,我也没有注意到NT移动指令。那么...为什么可以重新排序写入?

或者

中的内存是否重要

Writes to memory are not reordered

?因此,当我们有 ab 缓存时,写入不是写入主内存,而是写入缓存。

如果一个线程是 运行 foo 而另一个线程是 运行 bar 那么你的程序的行为将是 undefined.

您不能同时读取和写入非原子变量,例如 int

因此在这种情况下指令重新排序是允许的。

你的前提是错误的。只有编译时重新排序才能在 x861.

上破坏此示例

x86 asm 存储是发布存储。它们只能按程序顺序从存储缓冲区提交到 L1d 缓存。

a不能在b=1可见后仍然处于共享状态;这意味着线程 运行 foo 让其存储乱序提交。这就是 写入内存不会与其他写入重新排序 的意思,用于存储到可缓存内存。

如果它在被来自线程 运行 foo 的 RFO 无效后再次 处于共享状态,那么它将具有更新后的值 a.


脚注 1. 当然,自旋循环将优化为 if (b==0) infinite_loop,因为数据争用 UB 让编译器提升负载。参见 MCU programming - C++ O2 optimization breaks while loop

您似乎在询问 C 规则,同时假设代码将被天真地/直接翻译成 x86 asm。你可以用宽松的原子学来得到它,但不是 volatile 因为 volatile 访问不能(在编译时)与其他 volatile 访问重新排序。