【发布时间】:2019-01-15 16:04:33
【问题描述】:
我试图通过以下简单示例来理解指令重新排序:
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,发现如下:
对内存的写入不会与其他写入重新排序,与 以下例外:
— 使用 非临时移动指令(MOVNTI、MOVNTQ、MOVNTDQ、MOVNTPS 和 MOVNTPD);和
——字符串操作(参见第 8.2.4.1 节)。
这里没有字符串操作,我也没有注意到NT 移动指令。那么...为什么可以对写入进行重新排序?
或者说记忆在中重要吗
写入内存不会重新排序
?因此,当我们缓存了 a 和 b 并且写入不会发生在主内存中,而是发生在缓存中时。
【问题讨论】:
-
为什么你认为
a和b会被存储在内存中?在 C++ 语言中没有这样的要求,在极端情况下,编译器可能会生成将这两个仅保留在寄存器中的代码(例如)。 -
@Ped7g 是的,我问错了问题......对不起
-
没问题,搜索正确的问题是该过程的一部分,有时该过程需要像这样的步骤。 :) 但是这个话题可能很棘手,所以你必须更精确才能得到一些有意义的答案..
-
您需要在此处防止编译器重新排序。说在 x86/x64 上插入
a = 1; _ReadWriteBarrier(); b = 1;就足够了 -
这实际上是 C 还是 C++,或者您实际上是在询问按该顺序执行这些操作的程序集?因为显然这是 C 中的 UB,并且 C 内存模型适用于编译时重新排序和负载提升,而不是 x86 内存模型。 IIRC,您在上一个问题中这样做了,浪费了每个人的时间来整理 C 与 x86 内存模型,所以请在问题中说明您的实际意思是 asm 是否看起来像这样。显然
while(b == 0){}如果它完全进入循环,任何普通的 C 编译器都会变成无限循环。
标签: c assembly x86 memory-barriers