在观看this谈论LLVM中C ++ 11原子的实现时,有一段代码
-- Initially --
int x = 0;
std::atomic<bool> flag1{false}, flag2{false};
-- Thread 1 --
x = 42;
flag1.store(true, std::memory_order_release);
while(!flag2.load(std::memory_order_acquire));
x = 43;
-- Thread 2 --
while(!flag1.load(std::memory_order_acquire));
printf("%d", x);
flag2.store(true, std::memory_order_release);
我认为这个代码数据没有竞争(正如发言人所说):它永远不会打印除42
以外的任何内容。
但是,我不确定 它会打印42
。我的问题是:不允许编译器在线程1中通过while循环重新排序存储,以便两个线程都会死锁吗?或者C ++ 11标准的哪个部分阻止了这种行为?
答案 0 :(得分:0)
编译器必须永远不要将任何(外部可见)值的存储移动到释放栏之外,并且不得在读取栅栏上方移动读取。这是围栏的主要目的。
这里也可能涉及其他语义,例如,如果需要刷新缓存,释放围栏将刷新任何&#34;写入&#34;等待从这个CPU输出到主存储器。类似地,获取围栏将需要刷新所有或选定的区域,以便在下一次读取发出之前读入新值。
但是,所有现代CPU都在CPU之间具有连贯的内存,所以这不是问题 - 在某些不寻常/小型或旧CPU中可能存在一个问题,其中有一个缓存假定其他CPU不会读取相同的内容他们在缓存中的内存。如果您使用的是不一致的非统一处理器,那么缓存维护也会成为一个问题 - 您需要确保以正确的方式刷新缓存。同样,某些专业领域,但可能是多处理器系统中的一个重要因素。