C 语言原子操作
外观
C语言原子操作是一种在多线程编程中保证操作不可分割执行的机制,用于解决并发环境下的数据竞争问题。本条目将详细介绍其原理、标准库支持、使用场景及实际案例。
概述[编辑 | 编辑源代码]
原子操作指在多线程环境中,某个操作要么完全执行,要么完全不执行,不会被其他线程中断。C11标准引入<stdatomic.h>
头文件,提供对原子类型的原生支持。
关键特性:
- 不可分割性:操作过程中不会被线程调度打断
- 内存顺序控制:通过内存模型指定操作间的可见性关系
- 无锁编程基础:常用于实现锁-free数据结构
标准库支持[编辑 | 编辑源代码]
C11定义以下原子类型(部分):
类型别名 | 等效类型 |
---|---|
atomic_bool | _Atomic _Bool |
atomic_int | _Atomic int |
atomic_uint | _Atomic unsigned |
基本操作示例[编辑 | 编辑源代码]
#include <stdio.h>
#include <stdatomic.h>
int main() {
atomic_int counter = ATOMIC_VAR_INIT(0); // 初始化原子变量
// 原子递增
atomic_fetch_add(&counter, 1);
printf("Counter: %d\n", atomic_load(&counter));
// 比较交换操作
int expected = 1;
atomic_compare_exchange_strong(&counter, &expected, 2);
printf("After CAS: %d\n", atomic_load(&counter));
return 0;
}
输出示例:
Counter: 1 After CAS: 2
内存顺序[编辑 | 编辑源代码]
C11定义6种内存顺序,控制操作可见性:
常用组合:
- 加载:
memory_order_acquire
- 存储:
memory_order_release
- 读写:
memory_order_seq_cst
实际应用案例[编辑 | 编辑源代码]
无锁计数器[编辑 | 编辑源代码]
#include <stdatomic.h>
#include <threads.h>
atomic_long global_count;
int thread_func(void* arg) {
for (int i = 0; i < 100000; i++) {
atomic_fetch_add_explicit(&global_count, 1, memory_order_relaxed);
}
return 0;
}
自旋锁实现[编辑 | 编辑源代码]
typedef atomic_flag spinlock_t;
void lock(spinlock_t *s) {
while (atomic_flag_test_and_set_explicit(s, memory_order_acquire));
}
void unlock(spinlock_t *s) {
atomic_flag_clear_explicit(s, memory_order_release);
}
性能考量[编辑 | 编辑源代码]
原子操作比互斥锁更轻量,但在高争用场景仍需注意:
- 缓存行竞争(False Sharing)可通过填充解决
- 频繁的
seq_cst
可能成为瓶颈 - x86架构下部分操作有硬件优化
跨平台注意事项[编辑 | 编辑源代码]
- ARM等弱内存模型架构需显式指定内存屏障
- 旧版编译器可能需要
-std=c11
编译选项 - 某些嵌入式平台可能不支持所有原子类型