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

使用std::atomic compare_exchange_strong出现竞态条件,求分析非线程安全原因

代码线程不安全的核心原因分析

你的代码出现竞态条件的核心问题在于全局变量free是普通非原子类型,且被多个线程并发读写,具体拆解如下:

  • std::atomic::compare_exchange_strong的第二个参数是引用类型(T& expected):当CAS操作失败时,该函数会自动将expected的值更新为原子变量turn的当前值。
  • 两个线程共享同一个全局普通变量free作为expected参数:当其中一个线程CAS失败时,会修改free的值;而另一个线程同时在读取或修改free,这就造成了非原子的并发读写,属于C++标准定义的未定义行为。

举个典型的混乱场景:

  1. 线程1执行CAS时,free为0,CAS成功进入临界区;
  2. 此时线程2执行CAS,读取free的0值尝试修改turn,但失败(因为turn此时是1);
  3. compare_exchange_strong会把线程2的free更新为turn的当前值1;
  4. 线程1退出临界区时执行turn.store(free),但此时free已经被线程2改成了1,导致turn被设置为1而非初始的0;
  5. 后续两个线程的CAS逻辑彻底混乱,可能出现多个线程同时进入临界区,或某个线程永远无法获取执行权的情况。

另外补充:std::cout的输出操作本身并非线程安全,即使临界区逻辑正确,并发调用也可能导致输出内容错乱,但这是次要问题,核心矛盾还是free的非原子并发访问。

修复方案

最合理的修复是把free改为线程局部变量,让每个线程拥有独立的expected副本,避免互相干扰:

#include <iostream>
#include <thread>
#include <atomic>
#include <sched.h>

std::atomic<int> turn(0);

void Work(int pid){
    thread_local int free = 0; // 每个线程独立维护自己的预期值
    while(true){
        if(turn.compare_exchange_strong(free, pid)){
            std::cout << "Thread " << pid << " is running on core " << sched_getcpu() << std::endl;
            turn.store(0); // 直接写回空闲标记,无需依赖free
        }
    }
}

int main(){
    std::thread t1 = std::thread(Work, 1);
    std::thread t2 = std::thread(Work, 2);
    t1.join();
    t2.join();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 14:47:08