原子线程围栏:为什么在这个非原子变量上存在数据竞争?这有关系吗?

问题描述 投票:2回答:1

假设我们有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的write(事务)可能在读取之前没有完成吗?即使是这样,它真的是一个问题吗?

c++ multithreading c++11 atomic
1个回答
4
投票

TL;DR

这种数据竞争是危险的,您应该关心消除它。它可能不会因你的运气而显现,但它最终会引起头痛。

A bit longer

由于一些问题,此代码存在问题:

  1. 虽然编译Consumer编译器并不知道isDataReady可以在背景中改变,所以将while(!isDataReady)发出无限循环或者什么都没有是完全合理的(由于forward progress guarantee,正如评论中指出的那样)。
  2. 如果对bool的写入和/或读取不是原子的(在大多数平台上都不是这种情况,但理论上是可行的)任何读取都可能导致获取垃圾数据。
  3. 使用std::memory_order_release的内存栅栏可确保在其他线程使用std::memory_order_acquire调用fence之后可以看到线程中发生的更改(至少在简化中)。因此,bool变量的变化在其他线程中可能是不可见的。
  4. 由于现代处理器的超标量体系结构,操作可以在运行时由处理器重新排序。因此,从Producer可见的Consumer中的内存写入顺序可能与放在代码中的顺序不同。
© www.soinside.com 2019 - 2024. All rights reserved.