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

使用relaxed内存序能否保证flag.clear()先于互斥锁获取执行?

std::atomic_flag flag; // 类的成员变量
std::mutex m;

flag.test_and_set(); // 在f()或f2()执行前设为true

// 仅执行一次的“停止”函数
void f() {
    flag.clear(std::memory_order_relaxed);

    {
        std::unique_lock<std::mutex> lock(m);
        // 执行一些操作
    }
    // 等待f2线程结束
}

// 长期运行的函数
void f2() {
    std::unique_lock<std::mutex> lock(m);

    while (flag.test(std::memory_order_relaxed)) {
        // 执行循环操作
    }
}

问题

通常f2()先启动,f()用于终止f2()。我们需要保证flag.clear()在获取互斥锁之前执行,否则f()无法及时返回。

请问:使用relaxed内存序是否足以保证flag.clear()先于互斥锁获取操作执行?

另外延伸几个相关疑问:

  • 类似场景中std::thread::join作为同步操作能保证flag.clear()不会被重排到join之后,但这里用的是std::mutex,如果换成仅用acquire内存序的自旋锁,relaxed序是否依然安全?
  • acquire仅阻止后续操作重排到它之前,不限制存储操作重排到acquire之后,那这里是否需要StoreLoad屏障或全内存屏障?
  • 是不是必须用seq_cst内存序才能阻止互斥锁获取操作重排到flag.clear()之前?

回答

核心结论:relaxed内存序不足以保证flag.clear()先于互斥锁获取操作执行

1. 关于std::mutex的情况

std::mutex的锁获取操作(lock())是acquire语义,锁释放是release语义,但这里的关键是:CPU和编译器完全可能把flag.clear()(relaxed存储)重排到lock(m)之后。因为relaxed存储没有任何内存屏障约束,而acquire操作只禁止之后的读写操作被重排到acquire之前,不限制之前的存储操作被重排到acquire之后。

这就会导致:f()先去抢锁,抢到之后才执行flag.clear(),但此时f2()可能还持有锁在循环,f()会被阻塞在锁上,无法及时终止f2(),完全违背了设计意图。

2. 换成acquire自旋锁的情况

如果自旋锁的lock()只有acquire语义,情况和std::mutex完全一样——依然无法阻止flag.clear()被重排到锁获取之后。因为acquire语义不约束前面的存储操作向后重排,所以relaxed的clear()还是可能被放到锁获取之后执行,问题依然存在。

3. 需要什么内存屏障或内存序?

要阻止flag.clear()被重排到锁获取之后,我们需要在clear()和lock()之间插入StoreLoad屏障,或者直接给flag.clear()使用release语义(std::memory_order_release)。

  • 用release语义的话,release操作会禁止当前线程中后续的读写操作被重排到release之前,正好能保证flag.clear()一定在lock(m)之前执行。
  • 如果用relaxed+显式屏障,比如在clear()后插入std::atomic_thread_fence(std::memory_order_release),效果和直接用release语义的clear()一致。

至于seq_cst,它确实能解决问题,但属于“杀鸡用牛刀”——seq_cst会带来全序约束,性能开销比release大很多,这里完全没必要用,release语义就足够满足需求。

补充:为什么join能保证?

std::thread::join()是一个同步操作,它会强制线程中所有之前的内存操作完成后才会执行join之后的代码,同时也禁止之前的操作被重排到join之后。但mutex的lock操作没有这个约束,它只约束自身之后的操作,不约束之前的存储向后重排。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:05:30