C语言原子操作的实现示例

📅 2026/7/2 23:41:56 👁️ 阅读次数 📝 编程学习
C语言原子操作的实现示例

原子操作是并发编程中的一个核心概念。让我详细解释:

什么是原子操作?

原子操作是指在执行过程中不会被中断的操作,要么完全执行,要么完全不执行,不会出现部分执行的状态。

比喻理解

就像原子是不可分割的基本单位一样,原子操作是不可分割的操作单位。

非原子操作的问题

先看一个非原子操作的例子:

1

2

3

4

5

6

intcounter = 0;

// 这不是原子操作!

voidincrement() {

counter = counter + 1;

}

在汇编层面,这通常分为三步:

1

2

3

mov eax, [counter] ; 1. 读取counter到寄存器

inc eax ; 2. 寄存器值加1

mov [counter], eax ; 3. 写回内存

竞态条件问题

线程A:读取counter=0
线程B:读取counter=0
线程A:计算0+1=1
线程B:计算0+1=1
线程A:写入counter=1
线程B:写入counter=1 ← 结果应该是2,但实际是1!

C语言中的原子操作

C11标准引入的原子类型

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include <stdatomic.h>

// 声明原子变量

atomic_int atomic_counter = ATOMIC_VAR_INIT(0);

// 原子操作

voidincrement_atomic() {

atomic_fetch_add(&atomic_counter, 1);// 原子加法

}

intmain() {

atomic_counter = 5;// 原子存储

intvalue = atomic_counter;// 原子加载

printf("Counter: %d\n", value);

return0;

}

常见的原子操作函数

基本操作

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include <stdatomic.h>

atomic_int counter = ATOMIC_VAR_INIT(0);

// 加载和存储

intload_value = atomic_load(&counter);// 原子读取

atomic_store(&counter, 42);// 原子写入

// 交换操作

intold_value = atomic_exchange(&counter, 100);// 原子交换

// 比较交换(CAS - Compare And Swap)

intexpected = 100;

if(atomic_compare_exchange_strong(&counter, &expected, 200)) {

printf("CAS成功: 旧值=%d, 新值=200\n", expected);

}

算术运算

1

2

3

4

5

6

7

8

9

// 原子加法

intold = atomic_fetch_add(&counter, 5);// counter += 5,返回旧值

// 原子减法

atomic_fetch_sub(&counter, 3);// counter -= 3

// 原子自增/自减

atomic_fetch_add(&counter, 1);// counter++

atomic_fetch_sub(&counter, 1);// counter--

位运算

1

2

3

4

5

6

atomic_int flags = ATOMIC_VAR_INIT(0);

// 原子位操作

atomic_fetch_or(&flags, 0x01);// flags |= 0x01

atomic_fetch_and(&flags, ~0x01);// flags &= ~0x01

atomic_fetch_xor(&flags, 0x03);// flags ^= 0x03

原子操作的实际例子

1. 无锁计数器

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

#include <stdatomic.h>

#include <pthread.h>

#include <stdio.h>

atomic_int counter = ATOMIC_VAR_INIT(0);

void* worker(void* arg) {

for(inti = 0; i < 100000; i++) {

atomic_fetch_add(&counter, 1);// 原子自增

}

returnNULL;

}

intmain() {

pthread_t t1, t2;

pthread_create(&t1, NULL, worker, NULL);

pthread_create(&t2, NULL, worker, NULL);

pthread_join(t1, NULL);

pthread_join(t2, NULL);

printf("最终计数: %d (应该是200000)\n", atomic_load(&counter));

return0;

}

2. 自旋锁实现

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include <stdatomic.h>

typedefatomic_flag spinlock_t;

voidspinlock_init(spinlock_t* lock) {

atomic_flag_clear(lock);

}

voidspinlock_lock(spinlock_t* lock) {

// 忙等待,直到获得锁

while(atomic_flag_test_and_set(lock)) {

// 可选的:减少CPU占用

// __builtin_ia32_pause(); // x86的PAUSE指令

}

}

voidspinlock_unlock(spinlock_t* lock) {

atomic_flag_clear(lock);

}

3. 无锁栈(Lock-Free Stack)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

#include <stdatomic.h>

#include <stdlib.h>

typedefstructNode {

intdata;

structNode* next;

} Node;

typedefstruct{

_Atomic(Node*) top;

} LockFreeStack;

voidstack_init(LockFreeStack* stack) {

atomic_store(&stack->top, NULL);

}

voidstack_push(LockFreeStack* stack,intvalue) {

Node* new_node =malloc(sizeof(Node));

new_node->data = value;

Node* old_top;

do{

old_top = atomic_load(&stack->top);

new_node->next = old_top;

}while(!atomic_compare_exchange_weak(&stack->top, &old_top, new_node));

}

intstack_pop(LockFreeStack* stack) {

Node* old_top;

Node* new_top;

do{

old_top = atomic_load(&stack->top);

if(old_top == NULL)return-1;// 栈空

new_top = old_top->next;

}while(!atomic_compare_exchange_weak(&stack->top, &old_top, new_top));

intvalue = old_top->data;

free(old_top);

returnvalue;

}

内存顺序(Memory Order)

原子操作还涉及内存可见性问题:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include <stdatomic.h>

atomic_int data = ATOMIC_VAR_INIT(0);

atomic_int flag = ATOMIC_VAR_INIT(0);

// 生产者线程

voidproducer() {

atomic_store_explicit(&data, 42, memory_order_relaxed);

atomic_store_explicit(&flag, 1, memory_order_release);// 释放语义

}

// 消费者线程

voidconsumer() {

while(atomic_load_explicit(&flag, memory_order_acquire) == 0) {

// 等待

}

intvalue = atomic_load_explicit(&data, memory_order_relaxed);

printf("Data: %d\n", value);// 保证看到42

}

不同平台的原生原子操作

x86架构

1

2

3

4

5

6

7

8

9

10

// 内联汇编实现原子操作

intatomic_increment(int* value) {

__asm__ __volatile__(

"lock incl %0"// lock前缀确保原子性

:"+m"(*value)

:

:"cc"

);

return*value;

}

GCC内置原子操作

1

2

3

4

5

6

7

8

9

10

intcounter = 0;

// GCC内置的原子操作

voidincrement_gcc() {

__sync_fetch_and_add(&counter, 1);

}

intcompare_and_swap_gcc(int* ptr,intoldval,intnewval) {

return__sync_val_compare_and_swap(ptr, oldval, newval);

}

原子操作的优缺点

优点:

  • 高性能:避免锁的开销
  • 无死锁:不会出现锁顺序问题
  • 可扩展性:在多核系统中表现良好

缺点:

  • 复杂性:正确实现很困难
  • ABA问题:在CAS操作中可能出现
  • 平台依赖性:不同硬件支持程度不同