Skip to content

原子对象和原子操作

原子对象和原子操作是C11标准引入的重要特性,主要用于多线程编程中的同步操作,可以保证对共享变量的操作是原子的,避免数据竞争。

原子类型

C11标准在 <stdatomic.h> 头文件中定义了原子类型。最常用的原子类型包括:

c
atomic_bool              // bool 的原子版本
atomic_char              // char 的原子版本
atomic_int               // int 的原子版本
atomic_uint              // unsigned int 的原子版本
atomic_long              // long 的原子版本
atomic_ulong             // unsigned long 的原子版本
atomic_size_t            // size_t 的原子版本

也可以使用 _Atomic 关键字将任意类型转换为其原子版本:

c
_Atomic int counter;     // 声明原子整型对象

原子操作

基本原子操作

注:以下函数是为所有的原子类型 A 定义的泛型函数:类型 CA 对应的非原子类型。

  1. 原子存储和加载:

    c
    void atomic_store(volatile A* obj, C desired);    // 原子存储(原子写)
    C atomic_load(const volatile A* obj);             // 原子加载(原子读)

    上面两个函数默认以 memory_order_seq_cst 内存序执行读写操作。

    这两个函数有对应的 _explicit 版本,可以指定内存序:

    c
    void atomic_store_explicit(volatile A* obj, C desired, memory_order order);
    C atomic_load_explicit(const volatile A* obj, memory_order order);

    atomic_load_explicit 指定的内存序只能是 memory_order_acquirememory_order_relaxedmemory_order_consumememory_order_seq_cstatomic_store_explicit 指定的内存序只能是 memory_order_releasememory_order_relaxedmemory_order_seq_cst

    示例:

    c
    atomic_int counter = 0;
    atomic_store_explicit(&counter, 1, memory_order_release);
    int value = atomic_load_explicit(&counter, memory_order_acquire);
  2. 原子交换:

    c
    C atomic_exchange(volatile A* obj, C desired);  // 原子交换
  3. 原子比较与交换:

    c
    bool atomic_compare_exchange_strong(volatile A* obj,
                                        C* expected,
                                        C desired);
    bool atomic_compare_exchange_weak(volatile A* obj,
                                     C* expected,
                                     C desired);
    bool atomic_compare_exchange_weak_explicit(volatile A* obj,
                                              C* expected,
                                              C desired,
                                              memory_order success,
                                              memory_order failure);
    bool atomic_compare_exchange_strong_explicit(volatile A* obj,
                                                C* expected,
                                                C desired,
                                                memory_order success,
                                                memory_order failure);

原子算术操作

注:以下函数是为所有的原子类型 A 定义的泛型函数:类型 CA 对应的非原子类型;如果 A 为原子整数类型,则类型 MA 对应的非原子类型;如果 A 为原子指针类型,则类型 Mptrdiff_t

c
// 原子加法
C atomic_fetch_add(volatile A* obj, M arg);

// 原子减法
M atomic_fetch_sub(volatile A* obj, M arg);

// 原子与运算
C atomic_fetch_and(volatile A* obj, M arg);

// 原子或运算
C atomic_fetch_or(volatile A* obj, M arg);

// 原子异或运算
C atomic_fetch_xor(volatile A* obj, M arg);

内存序

原子操作可以指定内存序(memory order)来控制操作的顺序:

c
enum memory_order {
    memory_order_relaxed,     // 最宽松的内存序
    memory_order_consume,     // 消费序
    memory_order_acquire,     // 获取序
    memory_order_release,     // 释放序
    memory_order_acq_rel,     // 获取释放序
    memory_order_seq_cst      // 顺序一致性(默认)
};

示例:

c
atomic_int counter = 0;

// 使用指定的内存序进行原子操作
atomic_store_explicit(&counter, 1, memory_order_release);
int value = atomic_load_explicit(&counter, memory_order_acquire);

使用示例

一个使用原子操作的简单计数器示例:

c
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>

atomic_int counter = 0;

int thread_func(void* arg) {
    for (int i = 0; i < 1000000; i++) {
        atomic_fetch_add(&counter, 1);
    }
    return 0;
}

int main() {
    thrd_t th1, th2;
    
    // 创建两个线程
    thrd_create(&th1, thread_func, NULL);
    thrd_create(&th2, thread_func, NULL);
    
    // 等待线程结束
    thrd_join(th1, NULL);
    thrd_join(th2, NULL);
    
    printf("Final counter value: %d\n", atomic_load(&counter));
    return 0;
}

注意事项

  1. 原子操作通常比非原子操作慢,应该只在必要时使用。
  2. 原子操作主要用于多线程环境下的同步。
  3. 不同的内存序会影响性能和行为,应根据具体需求选择合适的内存序。
  4. 原子操作可以保证操作的原子性,但不能保证更复杂的同步需求,可能还需要互斥锁等其他同步机制。