You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用std::memory_order_seq_cst时std::atomic读写结果不确定?

问题分析与解答

核心误区:混淆单线程程序顺序与线程间执行顺序

你对std::memory_order_seq_cst的理解存在偏差:它保证的是所有seq_cst原子操作在全局范围内形成一个单一的总执行顺序,同时保证单线程内的操作遵循程序顺序,但这并不意味着不同线程的操作会自动按你期望的先后执行。

你的代码中,主线程的load操作和子线程的store操作之间没有任何**happens-before(先行发生)**关系:

  • 操作系统的线程调度是不确定的,主线程启动子线程后,可能立刻执行load(此时子线程还未运行,store没执行),也可能子线程先完成store后主线程才执行load。这就是输出不确定的根本原因,和内存连贯性无关。

为什么seq_cst没起到你预期的作用?

std::memory_order_seq_cst的全局总序特性,只保证:如果在这个总序里,子线程的store排在主线程的load之前,那么load一定能读到1234;反之则读到0。但它不会强制约束这两个操作的先后顺序——线程调度的随机性依然会导致两种结果都可能出现。

如何确保读到预期的1234?

要让主线程的load一定能看到子线程的store,需要建立明确的happens-before关系,比如:

  1. 将load放在t.join()之后:

    std::atomic<int> data(0);
    
    void func() {
      data.store(1234, std::memory_order_seq_cst);
    }
    
    int main() {
      std::thread t(func);
      t.join(); // 等待子线程完成,确保store先行发生于后续的load
      int val = data.load(std::memory_order_seq_cst);
      std::cout << "value: " << val << std::endl;
      return 0;
    }
    

    join()操作会确保子线程的所有操作(包括store)先行发生于主线程中join()之后的所有操作,因此load必然读到1234。

  2. 使用额外的原子同步标志:

    std::atomic<int> data(0);
    std::atomic<bool> ready(false);
    
    void func() {
      data.store(1234, std::memory_order_relaxed);
      ready.store(true, std::memory_order_seq_cst);
    }
    
    int main() {
      std::thread t(func);
      while (!ready.load(std::memory_order_seq_cst)) {} // 等待子线程完成store
      int val = data.load(std::memory_order_relaxed);
      std::cout << "value: " << val << std::endl;
      t.join();
      return 0;
    }
    

    这里ready的store和load建立了happens-before关系,确保data的store先行发生于data的load。

总结

  • 单线程内的程序顺序是确定的,但不同线程的操作默认没有固定的执行顺序,需要显式同步机制(如join、原子变量的同步关系、互斥量等)来建立happens-before约束。
  • std::memory_order_seq_cst保证全局总序,但不负责调度线程的执行顺序,它只是确保当操作的先后顺序被其他同步机制确定后,所有线程看到的操作顺序是一致的。

内容的提问来源于stack exchange,提问作者Benjamin Kim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 02:18:21