如何在C11中无锁实现比较与更新的原子操作?
无锁实现C11原子化条件更新
现有两个线程执行以下代码:
_Atomic volatile uint64_t foo; // 返回1表示更新了foo,返回0表示foo已经等于new值 int try_to_update_foo(uint64_t new_val) { if (foo < new_val) { foo = new_val; return 1; } return 0; }
需求是将foo < new_val的比较与foo = new_val的赋值合并为原子操作:当两个线程尝试将foo更新为同一个新值时,其中一个必须返回1,另一个返回0(顺序无关),且不使用信号量/互斥锁。
可以用C11标准提供的**原子比较交换(CAS)**操作实现,核心是atomic_compare_exchange_strong函数,它能原子地完成“比较-交换”逻辑,完美解决竞态问题。
实现代码
#include <stdatomic.h> _Atomic uint64_t foo; // volatile对原子类型是冗余的,C11原子类型本身保证内存可见性 int try_to_update_foo(uint64_t new_val) { uint64_t old_val = atomic_load(&foo); while (old_val < new_val) { // 原子比较:如果当前foo的值等于old_val,就把它换成new_val if (atomic_compare_exchange_strong(&foo, &old_val, new_val)) { return 1; // 更新成功 } // 如果比较失败,说明foo已经被其他线程修改,更新old_val后重试 } return 0; // 不需要更新(old_val >= new_val) }
关键说明
- 原子性保证:
atomic_compare_exchange_strong是硬件级别的原子操作,不会被线程调度打断,确保比较和赋值的原子性。 - 处理竞态场景:当两个线程同时尝试更新同一个
new_val时,只有一个线程能成功完成交换,返回1;另一个线程会发现old_val已经被修改为new_val,此时old_val < new_val不成立,循环退出,返回0,完全符合需求。 - 关于volatile:C11的
_Atomic类型已经隐含了内存可见性和禁止编译器优化的语义,不需要额外加volatile,加了属于冗余写法。 - weak vs strong:如果不需要严格避免虚假失败(部分平台可能出现),也可以用
atomic_compare_exchange_weak,性能可能略好,但需要保留同样的循环逻辑。
内容的提问来源于stack exchange,提问作者fadedbee
相关产品推荐
相关产品推荐

