跳转到内容

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种内存顺序,控制操作可见性:

graph LR A[Relaxed] --> B[Consume] B --> C[Acquire] C --> D[Release] D --> E[Acq_Rel] E --> F[Seq_Cst]

常用组合:

  • 加载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编译选项
  • 某些嵌入式平台可能不支持所有原子类型

参见[编辑 | 编辑源代码]