【问题标题】:Can compile-time memory reordering lead to deadlocks? [duplicate]编译时内存重新排序会导致死锁吗? [复制]
【发布时间】:2014-12-13 11:17:29
【问题描述】:

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

【问题讨论】:

  • @ParkYoung-Bae:问题是,存储和释放栅栏是否都可以通过以下循环(使用获取栅栏加载不相关的变量)?
  • @ParkYoung-Bae 另外,如果我理解正确,则必须将释放围栏放在 商店之前(如果有人愿意实施商店释放就释放围栏而言)。

标签: c++ c++11 concurrency stdatomic


【解决方案1】:

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

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

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

【讨论】:

  • 如果我理解正确的话,C++11 中的释放栅栏只会阻止加载和存储的重新排序超过任何后续存储。因此,如果释放栅栏紧随其后的是加载,编译器仍将被允许重新排序之前的存储超过该加载。另外,您没有回答问题。
  • 这就是为什么while(!flag2.load(std::memory_order_acquire)); 需要完全是一个获取栅栏,而不是(例如)释放栅栏。这要求在执行加载之前已完成任何先前的存储。我将尝试扩展我的答案,我正在处理其他事情,我可以看到这需要一些时间才能清楚地解释。
  • OP 中的代码不包含任何栅栏(至少在 C++11 意义上)。这些只是可以通过栅栏实现的简单原子(参见preshing.com/20130922/acquire-and-release-fences)。但其他实现是可能的,甚至是常见的。
  • 但是提供诸如std::memory_order_acquire 之类的“内存排序”的全部意义在于,从语言和编译器的角度来看,它们确实是内存排序障碍或栅栏。如果不是这样,这些类型的操作就永远无法预测,因为任何东西都可以跨任何东西移动——因此我们永远无法实现可靠的信号量、自旋锁或其他锁定机制。
  • @ParkYoung-Bae 可以区分两种类型的内存栅栏:a) 汇编中的栅栏和 b) C++11 中的 atomic_thread_fence。如上面引用的博客文章中所述,可以通过带有 atomic_thread_fence(release) 的 atomic-store-relaxed 来实现 atomic-store-release。这就是我想说的(用公认的笨拙的话)。无论如何,我建议在 C++ 上下文中,不应该以 release-fence 的名称来引用 atomic-store-release,就像这个答案在第一句话中所做的那样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-24
  • 1970-01-01
  • 2018-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多