C++中条件依赖atomic变量的双原子变量更新线程安全问题
std::atomic多线程同步问题解答
示例代码
// constructing atomics #include <iostream> // std::cout #include <atomic> // std::atomic #include <thread> // std::thread #include <vector> // std::vector std::atomic<int> a1{0}; std::atomic<int> a2{0}; void count1m (int id) { double local = id; double local2 = id*3; if(local > a1) { // a1 is an atomic variable so will reading it in if condition be atomic across threads or not? a1 = local; a2 = local2; } }; int main () { std::vector<std::thread> threads; std::cout << "spawning 20 threads that count to 1 million...\n"; for (int i=20; i>=0; --i) { threads.push_back(std::thread(count1m,i)); } for (auto& th : threads) th.join(); std::cout << "a1 = " << a1 << std::endl; }
疑问解答
问题1:在
if(local > a1)中,读取atomic变量a1的操作是否具备跨线程原子性?
是的,std::atomic类型的默认读取操作是原子的。这个读取操作会被CPU处理为不可分割的指令,不会出现读取到一半被其他线程打断、拿到中间无效值的情况,跨线程环境下读取结果是可靠的。问题2:若线程t1正执行该if判断,线程t2是否会等待t1完成a1的更新?
不会。std::atomic的读取操作本身不会触发线程阻塞或同步等待机制。t1读取a1的同时,t2可以毫无阻碍地读取甚至修改a1,两者的操作是并行的,没有强制等待的逻辑。问题3:是否可能出现一个线程更新a2、另一个线程更新a1的情况?
完全可能。当前代码里,if判断→更新a1→更新a2这一整套逻辑不是原子操作,三个步骤之间可能被其他线程打断。比如:- 线程A通过
if(local > a1)判断,更新了a1,但还没来得及更新a2; - 此时线程B读取到A更新后的a1,若B的local值更大,就会通过自己的if判断,开始更新a1;
- 这时就会出现线程A在更新a2,线程B在更新a1的场景,最终导致a1和a2的值不匹配(a1是B的local,a2是A的local2)。
- 线程A通过
如果要避免这种不一致,你需要把判断+更新的逻辑封装成原子操作:
- 方案一:使用
std::atomic::compare_exchange_strong配合循环,实现基于CAS的原子更新; - 方案二:用
std::mutex给整个if代码块加锁,确保同一时间只有一个线程执行判断和更新操作。
内容的提问来源于stack exchange,提问作者Pirate
相关产品推荐
相关产品推荐

