1

在观看有关 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 标准的哪一部分阻止了这种行为?

4

1 回答 1

0

编译器绝不能将任何(外部可见)值的存储移动到释放栅栏之外,并且不得将读取移动到获取栅栏之上。这是栅栏的主要用途。

这里可能还涉及其他语义,例如,如果需要刷新缓存,释放栅栏会将任何从该 CPU 挂起的“写入”刷新到主内存。类似地,获取栅栏将需要刷新所有或选定的区域,以便在发出下一次读取之前读入新值。

但是,所有现代 CPU 在 CPU 之间都具有一致的内存,因此这不是问题 - 这可能是一些不寻常/小型或旧 CPU 的问题,这些 CPU 具有假设其他 CPU 不会读取与它们相同的内存的缓存缓存。如果您使用的是不一致的非统一处理器,那么缓存维护也会成为一个问题 - 您需要确保以正确的方式刷新缓存。同样,这在某种程度上是一个专业领域,但在多处理器系统中可能是一个重要因素。

于 2014-12-13T12:01:58.007 回答