代码之家  ›  专栏  ›  技术社区  ›  Antoine Morrier

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

  •  2
  • Antoine Morrier  · 技术社区  · 7 年前

    假设我们有两个线程。一个生产者和一个消费者。我们有生产数据的生产者和使用数据的消费者。然而,守卫不是原子的!

    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 回复  |  直到 7 年前
        1
  •  4
  •   bartop    7 年前

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

    再长一点

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

    1. 编译时 Consumer 编译器不知道 isDataReady 可以改变背景,因此发射是完全合理的 while(!isDataReady) forward progress guarantee ,正如评论中指出的那样)。

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

    3. 记忆栅栏 std::memory_order_release std::memory_order_acquire (至少在简化方面)。因此,bool变量的变化可能在其他线程中不可见。

    4. 由于现代处理器的超标量结构, 处理器可以在运行时对操作重新排序 Producer 看得见 消费者 可能与代码中输入的不同。