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

C++中memory_order_acq_rel与seq_cst的混淆排序及死锁问题

C++原子内存序死锁分析:acq_rel vs seq_cst

死锁的核心原因

你遇到的死锁本质是**std::memory_order_acq_rel不保证原子操作的全局总序**,而seq_cst会强制所有原子操作(包括其他seq_cst操作)遵循一个统一的全局执行顺序。

当flag.store(false, acq_rel)时,这个操作仅保证:

  • 当前线程中,data.dec()的结果在flag.store(false)之前可见(release语义);
  • 当前线程中,后续操作不会被重排到flag.store(false)之前(acquire语义)。

但它不参与全局总序的约束,这就可能出现跨线程的操作顺序混乱:比如在多轮迭代中,dec_thread的flag.store(false)(acq_rel)和inc_thread的flag.store(true)(seq_cst)的全局执行顺序,可能与线程实际的执行顺序相反。dec_thread的下一次flag.load()(seq_cst)可能会读取到自己之前写入的false,完全看不到inc_thread已经写入的true,但此时data已经被inc_thread递增,最终导致dec_thread无限等待flag变为true,触发死锁。

为什么换成seq_cst就解决了问题

std::memory_order_seq_cst是最严格的内存序,它强制所有seq_cst原子操作遵循一个全局统一的总序,所有线程看到的操作顺序完全一致。

当flag.store(false)改为seq_cst后,所有对flag的操作(包括inc_thread的flag.store(true)和dec_thread的flag.load())都纳入了这个全局总序。这就保证了每一轮迭代的顺序严格符合预期:
inc_thread的data.inc() → flag.store(true) → dec_thread的flag.load()(读到true) → data.dec() → flag.store(false) → 下一轮迭代的inc_thread操作
不会出现操作顺序颠倒导致的可见性丢失,因此不会死锁。

保证无竞争的最宽松内存序配置

要维持你的流程正确性,只需要建立关键的happens-before关系,不需要全用seq_cst。最宽松的配置如下:

线程分工与内存序选择

  • inc_thread:

    1. 等待flag为false:使用flag.load(std::memory_order_acquire) —— 确保后续的data.inc()不会被重排到load之前,且能看到dec_thread写入的flag=false对应的所有操作。
    2. 递增data:使用data.fetch_add(1, std::memory_order_relaxed) —— data的修改仅需要通过flag的同步来保证可见性,不需要单独的内存序约束。
    3. 设置flag为true:使用flag.store(true, std::memory_order_release) —— 确保data.inc()的结果在flag.store之前可见,且对读取到flag=true的线程同步。
  • dec_thread:

    1. 等待flag为true:使用flag.load(std::memory_order_acquire) —— 确保后续的data.dec()不会被重排到load之前,且能看到inc_thread写入的flag=true对应的所有操作。
    2. 递减data:使用data.fetch_sub(1, std::memory_order_relaxed) —— 同理,依赖flag的同步保证可见性。
    3. 设置flag为false:使用flag.store(false, std::memory_order_release) —— 确保data.dec()的结果在flag.store之前可见,且对读取到flag=false的线程同步。

为什么这个配置可行

这套内存序通过release-acquire对建立了完整的同步链:

  • inc_thread的data.inc() happens before flag.store(true, release)
  • flag.store(true, release) synchronizes with dec_thread的flag.load(true, acquire)
  • dec_thread的flag.load(true, acquire) happens before data.dec()
  • data.dec() happens before flag.store(false, release)
  • flag.store(false, release) synchronizes with inc_thread的flag.load(false, acquire)
  • 最终形成循环的同步链,完全保证了操作的顺序和可见性,且内存序开销最小。

内容的提问来源于stack exchange,提问作者Jordan Woyak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 16:57:37