当前位置: 首页 > news >正文

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操作中可能出现
  • 平台依赖性:不同硬件支持程度不同
http://www.gsyq.cn/news/1623870.html

相关文章:

  • 野火预警中的黄金响应时间:动态计算与工程落地
  • Pytest API测试进阶:断言策略与插件生态实战指南
  • Python密钥管理实战:从生成到销毁的全生命周期安全指南
  • OAuth2.0授权码模式中CSRF攻击的防御:state参数与PKCE实战指南
  • Hutool RSA实战:Java非对称加密与数字签名完整指南
  • 高效漏洞通报:精炼模板与实战话术设计指南
  • 智能散热管理系统设计与DRV8213电机驱动器应用
  • 5步攻克res-downloader证书验证与反爬拦截实战指南
  • Kiran-shell 社区贡献指南:如何参与开源桌面面板项目开发
  • 实战指南:利用BurpSuite检测与修复Apache/Tomcat的TRACE方法漏洞
  • AES加密实战指南:从原理到跨平台实现与安全加固
  • AtomCode 21个内置工具全测评:从 read_file 到 web_fetch 的能力边界
  • 巧用 CSS 实现高频出现的复杂怪状按钮 - 镂空的内凹圆角边框
  • 如何快速搭建智能家居操作系统:Home Assistant OS完整指南
  • 红光磷光铱配合物 Ir(Btp)2(acac) OLED红光材料
  • GmSSL与Nginx集成实战:构建国密HTTPS服务器的完整指南
  • 2kW全桥LLC电源工程包:400V输入→48V输出,含Simulink可运行模型与Mathcad全流程参数计算
  • 无线网络安全实战:从漏洞修复到主动防御的完整指南
  • NATS消息中间件安全实践:TLS加密与认证授权全解析
  • Java实战AES-256-CBC文件加密解密:从原理到代码,彻底解决0x80071771错误
  • WinDbg 下载与安装教程(Microsoft.WinDbg 最新版)
  • 深度学习时间序列预测:从状态空间重建到业务落地
  • 网络安全实战:指纹识别技术原理与漏洞挖掘应用指南
  • 建设中页面模板:响应式布局+可调倒计时+全格式FontAwesome图标
  • RSA加密实战:从手工计算到Python代码实现与性能优化
  • BurpCrypto插件实战:一键解密加密流量,赋能Web安全测试
  • ZED双目相机直出点云+YOLOv4实时测距,不用标定就能跑
  • 知乎x-zse-96参数逆向分析:从JS混淆到Python纯算还原
  • FSCAN内网扫描实战:从主机发现到漏洞挖掘的全流程指南
  • 抖音直播弹幕实时抓取技术解析:基于系统代理的WebSocket数据采集方案