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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 06:28:21