使用std::atomic compare_exchange_strong出现竞态条件,求分析非线程安全原因
代码线程不安全的核心原因分析
你的代码出现竞态条件的核心问题在于全局变量free是普通非原子类型,且被多个线程并发读写,具体拆解如下:
std::atomic::compare_exchange_strong的第二个参数是引用类型(T& expected):当CAS操作失败时,该函数会自动将expected的值更新为原子变量turn的当前值。- 两个线程共享同一个全局普通变量
free作为expected参数:当其中一个线程CAS失败时,会修改free的值;而另一个线程同时在读取或修改free,这就造成了非原子的并发读写,属于C++标准定义的未定义行为。
举个典型的混乱场景:
- 线程1执行CAS时,
free为0,CAS成功进入临界区; - 此时线程2执行CAS,读取
free的0值尝试修改turn,但失败(因为turn此时是1); compare_exchange_strong会把线程2的free更新为turn的当前值1;- 线程1退出临界区时执行
turn.store(free),但此时free已经被线程2改成了1,导致turn被设置为1而非初始的0; - 后续两个线程的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
相关产品推荐
相关产品推荐

