c++ - 原子线程栅栏 : Why is there a data race on this non atomic variable? 这有关系吗?

标签 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 上会出现数据争用。 通常,正确的代码应该是对原子 bool 变量使用relaxed排序。

是否是因为对 isDataReady 的写入(事务)无法在读取之前完成?即使是这样,这真的是一个问题吗?

最佳答案

TL;DR

这种数据竞争很危险,您应该注意消除它。由于你的运气,它可能不会显现出来,但最终会引起头痛。

长一点

由于以下几个问题,此代码存在问题:

  1. 编译Consumer时,编译器不知道isDataReady可以在后台发生变化,因此发出while(!isDataReady)是完全合理的。 code> 无限循环或什么都没有(由于 forward progress guarantee ,正如评论中指出的那样)。

  2. 如果对 bool 的写入和/或读取不是原子的(大多数平台上并非如此,但理论上是可能的),任何读取都可能导致获取垃圾数据。

  3. 具有 std::memory_order_release 的内存栅栏可确保在其他线程使用 std::memory_order_acquire 调用栅栏后,线程中发生的更改将可见(位于至少在简化方面)。因此,bool 变量的变化在其他线程中可能是不可见的。

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

关于c++ - 原子线程栅栏 : Why is there a data race on this non atomic variable? 这有关系吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54110588/

相关文章:

multithreading - 线程 : Why must all user threads be mapped to a kernel thread?

c++ - 多线程服务器

c++ - 下标时是否必须使用 constexpr 数组?

c++ - 内部移动 std::vector 元素和 QVector

c++11 - 如何将64位整数拆分为2个32位整数?

c++ - 为什么 C++ 需要 6 大小的数组来存储 5 个字母的单词,而 C 只允许 5 个?

c++ - 如何在现代 OpenGL 中管理模型、 View 和投影矩阵

c# - Windows 服务内存使用量增加

c++ - 为什么 "most important const"必须是 const?

c++ - 如何使用 Boost.Test 库处理整数除以零异常?