原子对象和原子操作
原子对象和原子操作是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
定义的泛型函数:类型 C
为 A
对应的非原子类型。
原子存储和加载:
cvoid atomic_store(volatile A* obj, C desired); // 原子存储(原子写) C atomic_load(const volatile A* obj); // 原子加载(原子读)
上面两个函数默认以
memory_order_seq_cst
内存序执行读写操作。这两个函数有对应的
_explicit
版本,可以指定内存序:cvoid 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_acquire
、memory_order_relaxed
、memory_order_consume
或memory_order_seq_cst
;atomic_store_explicit
指定的内存序只能是memory_order_release
、memory_order_relaxed
或memory_order_seq_cst
。示例:
catomic_int counter = 0; atomic_store_explicit(&counter, 1, memory_order_release); int value = atomic_load_explicit(&counter, memory_order_acquire);
原子交换:
cC atomic_exchange(volatile A* obj, C desired); // 原子交换
原子比较与交换:
cbool 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
定义的泛型函数:类型 C
为 A
对应的非原子类型;如果 A
为原子整数类型,则类型 M
为 A
对应的非原子类型;如果 A
为原子指针类型,则类型 M
为 ptrdiff_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;
}
注意事项
- 原子操作通常比非原子操作慢,应该只在必要时使用。
- 原子操作主要用于多线程环境下的同步。
- 不同的内存序会影响性能和行为,应根据具体需求选择合适的内存序。
- 原子操作可以保证操作的原子性,但不能保证更复杂的同步需求,可能还需要互斥锁等其他同步机制。