C++ C++;11记忆模型:为什么可以';在优化过程中,编译器是否跨load()操作移动语句?

C++ C++;11记忆模型:为什么可以';在优化过程中,编译器是否跨load()操作移动语句?,c++,multithreading,c++11,atomic,memory-model,C++,Multithreading,C++11,Atomic,Memory Model,据我所知,对于顺序一致和acquire释放内存模型,如果一个线程的某些x.store(some_value)操作与另一个线程的x.load()操作同步,则: 规则1。在x.store(某些值)操作之前发生的所有内存操作必须出现在x.load()操作之前 这一点我似乎很清楚: -Thread 1- y = 1; x.store(2, memory_order_release); -Thread 2- if (x.load(memor

据我所知,对于顺序一致和acquire释放内存模型,如果一个线程的某些
x.store(some_value)
操作与另一个线程的
x.load()
操作同步,则:

规则1。在
x.store(某些值)
操作之前发生的所有内存操作必须出现在
x.load()操作之前

这一点我似乎很清楚:

-Thread 1-        
 y = 1;            
 x.store(2, memory_order_release);         

-Thread 2-
 if (x.load(memory_order_acquire) == 2)
   assert(y == 1)
这里,如果编译器将
y=1
操作放在
x.store(2)
之后,
assert
可能会失败,这不是我们期望的行为

规则2。在
x.load()
操作之后发生的所有内存操作也必须出现在
x.store(某些值)
操作之后

但现在我感到困惑:为什么编译器不能在
load()
操作之间移动语句?它如何违反程序的预期行为?我想到这样一个例子:

-Thread 1-        
 x.store(2, memory_order_release); // x == 0 initially       

-Thread 2-
 while (x.load(memory_order_acquire) == 1);
 y = 2; // y == 0 initially
在这里,如果编译器将
y=2
操作放在
while()
之前,
y
变为
2
(否则存在无限循环,
y
保持不变),但这个示例似乎是强制的(我甚至不确定编译器是否可以进行这种“优化”),我怀疑规则2是为更现实的情况制定的


您能解释一下规则2的必要性吗?

如果加载后的操作可以移动到加载前,线程2中的
断言(y==1)
可以在线程1中的
y=1
之前发生,即使(根据规则1)赋值发生在存储之前。只有这两条规则一起确保这两条语句以正确的顺序执行。

也许我误解了你的意思,但是
assert(y==1)
if
-分支中,那么编译器如何在加载之前移动它呢?实际的
assert
测试只有在
if
被计算之后才能进行,但在此之前,
y
的值可能会从内存中提取(进入运行线程2的CPU),这可能是因为编译器生成的汇编指令的顺序,也可能是因为CPU中的错误。如果数据不在CPU缓存中,则从内存中提取数据需要时间,因此CPU可能希望尽早开始提取
y
,以便在执行
assert
检查时该值可用。