Instruction reordering on intel

3

我正在尝试通过以下简单的示例来理解指令重排:

int a;
int b;

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

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

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

对内存的写入操作不会与其他写入操作重排序,但以下情况除外:

—使用非临时移动指令(MOVNTI、MOVNTQ、MOVNTDQ、MOVNTPS和MOVNTPD)执行的流式存储(写入);以及

—字符串操作(参见第8.2.4.1节)。

这里没有字符串操作,也没有发现NT的移动指令。那么...为什么会出现写入重排序?
还是说,

对内存的写入操作不会被重排序?

因此,当我们将ab缓存起来,并且写入操作并不是针对主存而是针对缓存时,它们可以重排序。

你为什么认为ab会被存储在内存中?在C++语言中并没有这样的要求,在极端情况下,编译器可能会生成仅将这两个变量存储在寄存器中的代码(例如)。 - Ped7g
2
没问题,寻找正确的问题是过程的一部分,有时这个过程需要像这样的步骤。 :) 但是这个主题可能相当棘手,所以你需要更精确才能得到有意义的答案。 - Ped7g
2
这实际上是C还是C++,还是你实际上在询问按那个顺序执行这些操作的汇编?因为显然这在C中是未定义的,而C内存模型适用于编译时重新排序和负载提升,而不是x86内存模型。如果我没记错的话,你在以前的问题中做过这件事,并浪费了每个人的时间来解决C与x86内存模型的区别,请在问题中明确指出您实际上是否意味着汇编看起来像这样。显然,如果进入循环,任何正常的C编译器都会使while(b == 0){}成为无限循环。 - Peter Cordes
@PeterCordes,实际上由于存储缓冲区和高速缓存一致性问题,另一个线程观察到了foo所做的写入顺序不同。然而,在我引用的手册中明确指出,对内存的写入不能与其他写入重新排序。 - St.Antario
如果您实际上按照x86汇编中的意思进行操作,那么看到 b!=0 将确保您也看到 a==1,因为 mov [b], 1 是释放存储(与除NT之外的所有x86存储一样),因为x86要求存储以程序顺序从存储缓冲区提交到 L1d。(因此不允许重新排序。只有在编译时重新排序才会在x86上破坏此示例)。但是,如果编译了此无效的C代码,则情况并非如此。您是否声称您实际上重现了所述的重新排序?如果是这样,请发布一个[mcve]。 - Peter Cordes
显示剩余9条评论
2个回答

4
如果一个线程正在运行foo,而另一个线程正在运行bar,那么您的程序的行为将是未定义的。
您不被允许在非原子变量(例如int)上进行同时读写操作。
因此,在这种情况下可以进行指令重排序。

如果它们对齐相应的话...但无论如何都是未定义行为。 - St.Antario
是的,我同意对齐。但是我在代码中没有看到任何覆盖默认对齐方式的编译指示。因此,假设int的自然对齐方式。在这种情况下,我没有看到任何未定义行为。当然,需要强制编译器不要重新排序“a=1,b=1”。 - RbMm

3
您的前提是错误的。只有编译时重新排序才能在x86上破坏此示例。
x86汇编存储是释放存储。它们只能按程序顺序从存储缓冲区提交到L1d高速缓存中。
b=1可见之后,a不能仍然处于共享状态;这意味着运行foo的线程让其存储无序提交。对于可缓存内存的存储,这就是“内存写入不与其他写入重排序”的含义。
如果在被运行foo的线程的RFO使其失效后再次处于共享状态,则其将具有a的更新值。

注脚1. 当然,自旋循环将优化为if(b == 0)infinite_loop,因为数据竞争UB使编译器提升了负载。请参见 MCU编程-C ++ O2优化破坏while循环

您似乎在询问C规则,同时假设代码将被直接转换为x86汇编语言。您可以通过松散的原子操作获得这一点,但不能使用volatile,因为volatile访问无法与其他volatile访问(在编译时)重新排序。


就像我之前说的那样,当时我意思是提供x86汇编代码示例,但是却错误地提供了一份 C 代码示例。 - St.Antario
@St.Antario:我重新添加了C标签,因为这是我能想到的你声称“在这个例子中,已知断言可能失败”的唯一原因。请参阅http://preshing.com/20120930/weak-vs-strong-memory-models/和http://preshing.com/20120625/memory-ordering-at-compile-time/。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接