无同步时,通过relaxed原子操作选中的值非原子更新是否安全?
在无同步情况下,对relaxed原子操作选中的值执行非原子更新是否安全?
示例伪代码
struct Values{ AtomicInt counter; Int needed_counter; // 我们要更新的字段 SomeType unsynchronized_value; } fn update_array(Values[] values){ for(Values& val : values) { // 假设不会发生溢出 if (val.counter.fetch_add(1, relaxed) != val.needed_counter) { // 判断条件 continue; } // 对CPU无操作,但阻止编译器跨栅栏重排指令 compiler_fence(acquire_release); UpdateUnsynchonisedValue(&mut val.unsynchronized_value); } // 一次性刷新当前线程的所有修改 memory_fence(release); }
安全性分析
你的核心疑问是:现代CPU的乱序/推测执行是否会让UpdateUnsynchonisedValue在条件判断前执行,进而引发数据竞争。结合C++/Rust的内存模型和CPU行为,可以从以下几点拆解:
编译器层面的保障
你添加的compiler_fence(acquire_release)已经完全阻止了编译器的指令重排——编译后的代码中,条件判断逻辑必然在UpdateUnsynchonisedValue执行之前,不会出现编译器层面的提前执行。CPU推测执行的影响
即使CPU做了推测执行,提前执行了UpdateUnsynchonisedValue,也不会引发数据竞争:- 你的条件逻辑确保只有一个线程会满足条件:
fetch_add(1, relaxed)是原子操作,每个线程对counter的递增都是独占的,只有当某个线程读取到的counter原值恰好等于needed_counter时,才会进入更新逻辑。其他线程都会因条件不满足直接跳过。 - 对于条件不满足的线程,CPU的推测执行结果会被回滚,不会将
UpdateUnsynchonisedValue的修改写入内存,自然不会和其他线程的操作产生冲突。
- 你的条件逻辑确保只有一个线程会满足条件:
CPU乱序执行的边界
CPU的乱序执行不会打破原子操作的语义,也不会让原子操作的结果依赖于后续非原子操作的执行。即使没有CPU内存栅栏,fetch_add(relaxed)的原子性也能保证条件判断的正确性,而只有条件满足的线程才会提交更新操作,后续的memory_fence(release)则确保该线程的修改能被其他线程可见(如果有读取逻辑的话)。
结论
这种操作是安全的,不会引发数据竞争。只要你的条件逻辑确实能保证只有一个线程进入更新流程,即使依赖relaxed原子操作和编译器栅栏,也不会出现线程间的冲突。
内容的提问来源于stack exchange,提问作者Angelicos Phosphoros
相关产品推荐
相关产品推荐

