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

关于__ATOMIC_RELAXED结合if语句的指令重排问题咨询

问题分析与解答

代码示例

int flag = 0;

int threadA()
{
    if(__atomic_load_n(&flag, __ATOMIC_RELAXED))
    {
        return -1;
    }

    // do something A

    return 0;
}

int threadB()
{
    __atomic_store_n(&flag, 1, __ATOMIC_RELEASE);

    // do something B

    __atomic_store_n(&flag, 0, __ATOMIC_RELEASE);

    return 0;
}

需求说明

当threadB()执行// do something B时,不希望threadA()执行相关操作。

核心疑问

由于__ATOMIC_RELAXED不阻止指令重排,threadA()中的// do something A是否可能在if语句之前执行?


解答

1. 直接结论:不会发生这种重排

即使使用__ATOMIC_RELAXED内存序,threadA里的// do something A也不可能在if(__atomic_load_n(...))判断之前执行。

2. 原因解释

指令重排的规则不会破坏单线程内的程序顺序一致性——也就是站在当前线程的视角,代码的执行逻辑必须符合你写的顺序。

  • 对于threadA来说,// do something A在if分支的外部,只有当if条件不成立(flag为0)时才会执行。编译器和CPU无论怎么重排指令,都不能让这段代码跑到if判断之前,否则会彻底违背单线程的逻辑语义。
  • __ATOMIC_RELAXED的“不阻止重排”,指的是不同线程之间的操作可见性和顺序性约束,而非单线程内部的逻辑顺序。它不会允许编译器/CPU把后续代码提前到分支判断之前执行。

3. 当前代码的线程安全隐患

虽然你担心的重排不会发生,但这段代码的内存序搭配无法满足核心需求:threadB执行do something B时,threadA仍可能进入执行do something A。
原因是threadA用__ATOMIC_RELAXED加载flag,threadB用__ATOMIC_RELEASE存储flag,两者之间没有同步关系。threadB设置的flag=1可能无法及时被threadA看到,导致threadB已在执行do something B,threadA还读到flag=0并进入执行。

4. 修复方案

要满足需求,需要给threadA的原子加载加上__ATOMIC_ACQUIRE内存序,和threadB的__ATOMIC_RELEASE形成ACQUIRE-RELEASE同步:

int threadA()
{
    // 用ACQUIRE加载,和RELEASE存储建立同步
    if(__atomic_load_n(&flag, __ATOMIC_ACQUIRE))
    {
        return -1;
    }

    // do something A

    return 0;
}

这样:

  • threadB的__ATOMIC_RELEASE存储会保证// do something B之前的所有操作(包括设置flag=1)对后续用__ATOMIC_ACQUIRE加载flag的线程可见;
  • threadA的__ATOMIC_ACQUIRE加载会保证,只有当它看到flag=0时,后续的// do something A才会执行,且能看到threadB之前的所有已完成操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 16:41:04