原子线程防护:为什么在此非原子变量上存在数据竞争?有关系吗?

时间:2019-01-09 12:51:57

标签: c++ multithreading c++11 atomic

假设我们有2个线程。一位生产者和一位消费者。我们拥有生产数据的生产者和使用该数据的消费者。但是,后卫不是原子的!

bool isDataReady = false;
int data = 0;

void Producer() {
  data = 42;
  std::atomic_thread_fence(std::memory_order_release);
  isDataReady = true;
}

void Consumer() {
  while(!isDataReady);
  std::atomic_thread_fence(std::memory_order_acquire);
  assert(data == 42);
}

我想知道为什么isDataReady上发生了数据竞赛。 通常,正确的代码应该是对原子布尔变量使用relaxed排序。

是因为对isDataReady的写入(事务)可能在读取之前未完成?即使是这样,这真的有问题吗?

1 个答案:

答案 0 :(得分:4)

TL; DR

此数据竞赛非常危险,您应该注意消除它。它可能不会因您的运气而显现出来,但最终会引起头痛。

再长一点

由于一些问题,此代码有问题:

  1. 尽管编译Consumer的编译器不知道isDataReady可以在后台更改,所以发出while(!isDataReady)无限循环或什么也不发出(由于{{ 3}},正如评论中指出的那样。

  2. 如果对bool的写入和/或读取不是原子的(在大多数平台上不是这种情况,但从理论上讲是可能的),则任何读取都会导致获取垃圾数据。

    < / li>
  3. 带有std::memory_order_release的内存隔离栅确保在其他线程调用带有std::memory_order_acquire的篱笆之后,线程中发生的更改将是可见的(至少是为了简化)。因此,布尔变量的更改可能在其他线程中不可见。

  4. 由于现代处理器的超标量体系结构,操作可能会在运行时由处理器重新排序。因此,从Producer可见的Consumer中的内存写入顺序可能与代码中的写入顺序不同。