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

原子操作(Atomic Operation) 是指不可被中断的操作——要么完整执行,要么完全不执行

在计算机科学中,原子操作(Atomic Operation) 是指不可被中断的操作——要么完整执行,要么完全不执行,在操作过程中不会被其他线程或进程打断。这种特性确保了多线程环境下对共享资源的操作不会中间状态,从而避免竞态条件(Race Condition)。

核心特点

  1. 不可分割性:操作的所有步骤作为一个整体完成,不会被任何外部事件(如线程调度、中断)拆分。
  2. 无中间状态:其他线程只能看到操作执行前或执行后的状态,看不到执行过程中的临时状态。
  3. 硬件支持:通常由CPU的原子指令(如带锁前缀的汇编指令)提供底层支持,而非纯软件实现。

为什么需要原子操作?

在多线程场景中,看似简单的操作(如 count++)实际包含多个步骤(读取→修改→写入),若被其他线程打断,会导致数据不一致:

int count = 0;// 线程1执行
count++;  // 步骤1:读取count=0 → 步骤2:+1 → 步骤3:写入1// 线程2执行(若在线程1步骤1后、步骤3前被调度)
count++;  // 同样读取到0,最终结果可能为1(错误),而非预期的2

原子操作通过将这三步合并为一个不可分割的指令,确保上述情况不会发生。

原子操作的实现方式

  1. 硬件层面
    CPU提供原子指令(如x86的 LOCK 前缀指令),执行时会锁定总线或缓存,阻止其他CPU核心同时访问该内存地址。例如:

    • LOCK INC [count]:原子递增内存中的 count 值。
    • LOCK CMPXCHG:原子比较并交换(Compare-and-Swap,CAS)操作。
  2. 软件层面
    编程语言或库通过封装硬件原子指令,提供高层接口(如C11的 <stdatomic.h>、C++的 std::atomic、Linux的 atomic_t)。

常见原子操作类型

  1. 原子读写:对变量的读取或写入操作是原子的(如32位整数的读写在多数CPU上天然是原子的)。

  2. 原子修改

    • 自增(atomic_inc)、自减(atomic_dec
    • 加法(atomic_add)、减法(atomic_sub
    • 比较并交换(CAS:Compare-And-Swap):若当前值等于预期值,则更新为新值,返回操作是否成功。
  3. 原子位操作:对变量的特定位进行原子置位、清零或翻转。

代码示例(C语言,使用C11标准)

#include <stdatomic.h>
#include <pthread.h>
#include <stdio.h>// 定义原子变量(int类型)
atomic_int count = 0;// 线程函数:原子递增count
void *thread_func(void *arg) {for (int i = 0; i < 10000; i++) {// 原子自增操作(不可分割)atomic_fetch_add(&count, 1);}return NULL;
}int main() {pthread_t tid1, tid2;pthread_create(&tid1, NULL, thread_func, NULL);pthread_create(&tid2, NULL, thread_func, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);// 输出结果一定是20000(无竞态条件)printf("count = %d\n", atomic_load(&count));return 0;
}

说明
atomic_fetch_add 会将 count 原子递增1,替代了非原子的 count++,确保两个线程并发操作的正确性。

原子操作 vs 互斥锁

特性原子操作互斥锁(Mutex)
粒度单个变量的简单操作(如增减、赋值)任意代码块(临界区)
性能极高(仅需硬件指令,无上下文切换)较低(可能导致线程阻塞/唤醒)
适用场景简单数值操作(计数、标记位)复杂操作(如链表修改、多变量更新)
实现依赖硬件指令支持操作系统或库实现

注意事项

  1. 适用范围有限:原子操作仅适用于简单的变量操作,无法保护复杂的代码块(如多步逻辑、链表操作)。
  2. 类型限制:通常只支持整数、指针等基本类型,不直接支持结构体等复杂类型。
  3. 内存顺序:高级原子操作需考虑内存可见性(如C11的内存序:memory_order_seq_cstmemory_order_acquire等),确保多线程间的数据同步。

总结

原子操作是多线程编程中轻量级的同步机制,通过硬件保证的不可分割性,高效解决简单共享变量的并发访问问题。与互斥锁相比,它性能更高但适用场景更窄,常作为底层同步原语(如实现锁、信号量)或优化简单计数场景。

http://www.dtcms.com/a/361435.html

相关文章:

  • Android修改进程优先级
  • 在IDEA里使用Google Java Format
  • UART控制器——ZYNQ学习笔记14
  • 解决Content Security Policy (CSP)问题
  • Sparse4Dv3 部署到 TensorRT-(1)
  • Gradle vs. Maven,Java 构建工具该用哪个?
  • Paimon MergeTreeWrite、Compaction 和 快照构建
  • 嵌入式解谜日志之Linux操作系统—进程间的通信(IPC):无名管道,有名管道,信号通信5
  • 单片机元件学习
  • 【stm32】定时器(超详细)
  • Git安装教程
  • 【51页PPT】智慧社区解决方案(附下载方式)
  • 审美积累 | 金融类 SaaS 产品落地页设计
  • Empire: LupinOne靶场渗透
  • 贪心算法解决固定长度区间覆盖问题:最少区间数计算
  • CICD实战(2) - 使用Arbess+GitLab+SonarQube实现Java项目快速扫描/构建/部署
  • 【MySQL详解】索引、事务、锁、日志
  • 【C++上岸】C++常见面试题目--数据结构篇(第十六期)
  • 科学研究系统性思维的方法体系:数据收集
  • 11,FreeRTOS队列理论知识
  • linux内核 - ext 文件系统介绍
  • 嵌入式学习日志————I2C通信外设
  • 拥抱智能高效翻译 ——8 款视频翻译工具深度测评
  • Linux Shell 脚本中括号类型及用途
  • 【项目思维】嵌入式产业链与技术生态
  • 2025 最新React前端面试题目 (9月最新)
  • Windows Qt5.15.17源码使用VS2019编译安装
  • 六、练习3:Gitee平台操作
  • 瑞芯微RK3576平台FFmpeg硬件编解码移植及性能测试实战攻略
  • 深入掌握 Flask 配置管理:从基础到高级实战