C++八股 —— 原子操作

文章目录

    • 1. 什么是原子操作
    • 2. 原子操作的特点
    • 3. 原子操作的底层原理
    • 4. 内存序
      • 内存屏障
    • 5. 原子操作和互斥锁的对比
    • 6. 常用的原子操作
    • 7. 相关问题讨论

参考

  • C++ atomic 原子操作_c++ 原子操作-CSDN博客
  • DeepSeek

1. 什么是原子操作

原子操作(Atomic Operations)是不可分割的操作,保证在多线程环境中执行时不会被中断,避免数据竞争(Data Race)。即:原子操作要么完全执行,要么完全不执行,不会在执行期间被其他线程操作干扰。

C++11引入<atomic>头文件,提供std::atomic<T>模板类,支持对基本类型(如intbool、指针)的原子操作。

2. 原子操作的特点

  • 无锁(Lock-Free): 原子操作通常由硬件指令(如CAS,LL/SC)实现,无需显式加锁。
  • 线程安全: 保证对变量的读写操作在多线程环境下的正确性。
  • 轻量级: 适合简单操作(如计数器、标志位),性能通常高于互斥锁。

示例:

#include <atomic>
std::atomic<int> counter(0);void increment() {counter.fetch_add(1, std::memory_order_relaxed); // 原子递增
}

3. 原子操作的底层原理

原子操作的实现依赖于硬件指令,例如:

  • CAS(Compare-And-Swap):通过比较内存中的值与预期值,若匹配则更新为新值。

    bool compare_exchange_strong(T& expected, T desired) {if (current == expected) {current = desired;return true;} else {expected = current;return false;}
    }
    
  • LL/SC(Load-Linked/Store-Conditional):在特定地址上标记“监视”,若未被其他线程修改则写入。

这些指令保证操作的原子性,但不同硬件(x86、ARM)的实现差异较大。例如:

  • x86:通过LOCK前缀指令(如LOCK XCHG)实现原子操作。
  • ARM:依赖LL/SC指令实现无锁原子操作。

原子操作的局限性

  • ABA问题:线程A读取值A,线程B将值改为B后又改回A,导致A的CAS误判无变化。
    解决方案:使用带版本号的原子变量(如std::atomic<std::pair<T, uint64_t>>)。
  • 适用范围:仅适用于基本类型(如intbool、指针)。复杂类型需使用std::atomic_flag或互斥锁。

4. 内存序

内存序(Memory Order)定义了原子操作之间的可见性顺序约束,确保多线程环境下的内存访问符合预期。以下问题可能导致指令顺序变化:

  • 编译器重排:编译器优化可能导致指令顺序变化。
  • CPU重排:现代CPU的乱序执行机制(如Store Buffer、Invalidate Queue)可能打乱指令顺序。
  • 缓存一致性:不同核心的缓存状态可能导致内存视图不一致。

C++提供6种内存序,分为三类:

内存序描述
顺序一致性(Sequential Consistency)
memory_order_seq_cst最严格,保证全局顺序一致,性能较低。默认选项。
获取-释放(Acquire-Release)
memory_order_acquire保证后续读操作不会重排到该操作之前(用于“获取”同步)。
memory_order_release保证前面的写操作不会重排到该操作之后(用于“释放”同步)。
memory_order_acq_rel同时包含acquire和release语义(用于读-改-写操作)。
宽松(Relaxed)
memory_order_relaxed仅保证原子性,无顺序约束(适用于计数器等无需同步的场景)。
memory_order_consume依赖顺序(较弱的acquire,C++17后不推荐使用)。

典型场景:

生产者-消费者模型:

// 生产者线程
data = ...; // 生产数据
flag.store(true, std::memory_order_release); // 发布数据// 消费者线程
while (!flag.load(std::memory_order_acquire)); // 获取数据
use_data(data); // 安全使用数据

内存屏障

1. 内存屏障的作用

内存屏障是硬件或编译器级别的指令,用于强制限制内存操作的执行顺序,分为两类:

  • 编译器屏障:阻止编译器重排指令(如asm volatile("" ::: "memory"))。
  • 硬件屏障:阻止CPU重排内存访问(如x86的MFENCE、ARM的DMB)。

2. C++内存序与内存屏障的映射

  • std::atomic_thread_fence():显式插入内存屏障。

    std::atomic_thread_fence(std::memory_order_acquire); // 插入读屏障
    
  • 隐式屏障:原子操作的内存序参数隐式插入屏障:

    a.store(1, std::memory_order_release); // 隐式插入Store屏障
    

3. 内存屏障的实际案例

示例:无锁队列的入队操作

// 生产者线程
Node* new_node = new Node(data);
new_node->next.store(head, std::memory_order_relaxed);
head.store(new_node, std::memory_order_release); // 插入写屏障,确保new_node初始化完成后再更新head// 消费者线程
Node* local_head = head.load(std::memory_order_acquire); // 插入读屏障,确保读取到最新的head
if (local_head != nullptr) {// 安全操作local_head->next
}

5. 原子操作和互斥锁的对比

特性原子操作互斥锁(如std::mutex)
实现方式硬件指令(如CAS)实现无锁操作。通过操作系统内核的锁机制(可能涉及上下文切换)。
性能低竞争时性能高,高竞争时可能自旋。高竞争时可能更高效(线程休眠)。
适用场景简单操作(如计数器、标志位)。复杂操作或需要保护多个变量/代码块。
内存序复杂性需显式指定内存序,易出错。隐式保证顺序一致性,更简单。
死锁风险无。需避免死锁(如加锁顺序不一致)。
ABA问题可能发生(需配合版本号解决)。无。

选择建议:

  • 使用原子操作:需要高性能的简单操作,且能正确处理内存序。
  • 使用互斥锁:保护复杂逻辑或临界区较长时,简化代码并减少错误。

6. 常用的原子操作

  • load:读取原子变量的值

    std::atomic<int> a(1);
    int value = a.load();
    
  • store:将一个值存储到原子变量中

    std::atomic<int> a(1);
    a.store(2); // a的值变为2
    
  • exchange:将原子变量的值替换为另外一个值,并返回旧值

    常用来在并发环境下进行“交换”操作。

    std::atomic<int> a(1);
    int old_value = a.exchange(2); // old_value为1,a的值变为2
    
  • compare_exchange_weak / compare_exchange_strong:原子地进行条件交换操作。若当前值等于预期值,则交换新值,否则返回falseweak失败后可能会重新尝试,性能相对较高;strong失败后会返回false并不再尝试。

    std::atomic<int> a(1);
    int expected = 1;
    if (a.compare_exchange_weak(expected, 2)) {// 如果a的值是1,设置为10std::cout << "Value changed!" << std::endl;
    } else {std::cout << "Value not changed!" << std::endl;
    }
    
  • fetch_add / fetch_sub:原子地执行加法或减法操作,并返回旧值。

    std::atomic<int> a(5);
    int old_value = a.fetch_add(1);  // old_value为5,a为6
    

7. 相关问题讨论

  • 使用 std::atomic 实现线程安全计数器:C++ atomic 原子操作_c++ 原子操作-CSDN博客
  • 使用 compare_exchange_strong 实现自旋锁:C++ atomic 原子操作_c++ 原子操作-CSDN博客
  • 原子操作支持的运算和不支持的运算:C++ atomic 原子操作_c++ 原子操作-CSDN博客
  • 什么是ABA问题,如何解决:ABA问题及其解决思路C+±CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/82428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

双紫擒龙紫紫红指标源码学习,2025升级版紫紫红指标公式-重点技术

VAR1:MA((LOWHIGHCLOSE)/3,5); VAR2:CLOSEHHV(C,4) AND REF(C,1)LLV(C,4); 双紫擒龙:REF(C,1)LLV(C,4) AND C>REF(C,2) OR REF(C,2)LLV(C,4) AND REF(C,1)<REF(C,3) AND REF(C,2)<REF(C,4) AND C>REF(C,1); VAR4:VAR1>REF(VAR1,1) AND REF(VAR1,1)<REF(VAR1,…

NeuralRecon技术详解:从单目视频中实现三维重建

引言 三维重建是计算机视觉领域中的一项关键技术&#xff0c;它能够从二维图像中恢复出三维形状和结构。随着深度学习的发展&#xff0c;基于学习的方法已经成为三维重建的主流。NeuralRecon是一种先进的三维重建方法&#xff0c;它能够从单目视频中实时生成高质量的三维模型。…

Ubuntu 上开启 SSH 服务、禁用密码登录并仅允许密钥认证

1. 安装 OpenSSH 服务 如果尚未安装 SSH 服务&#xff0c;运行以下命令&#xff1a; sudo apt update sudo apt install openssh-server2. 启动 SSH 服务并设置开机自启 sudo systemctl start ssh sudo systemctl enable ssh3. 生成 SSH 密钥对&#xff08;本地机器&#xf…

MySQL 索引的增删改查

MySQL 索引的增删改查 1 建表时创建索引 [UNIQUE|FULLTEXT|SPATIAL] INDEX|KEY [别名] (字段名 [(长度)] [ASC|DESC] )主键直接写&#xff1a; PRIMARY KEY (Id)例如&#xff1a; CREATE TABLE people (id int NOT NULL PRIMARY KEY AUTO_INCREMENT,last_name varchar(10)…

为什么现代CSS应该选择OKLCH:从颜色科学到设计系统革新

在数字界面中&#xff0c;颜色不仅是美学的载体&#xff0c;更是信息传递的重要工具。CSS Color Level 4 标准引入了 OKLCH 颜色空间, 提供​​感知均匀性​​&#xff08;颜色差异与实际视觉感受一致&#xff09;&#xff0c;解决传统HSL/HSV在调整颜色时的不自然问题。文本帮…

【java】小练习--零钱通

文章目录 前言一、项目开发流程说明二、功能实现2.1 菜单2.2 零钱通明细2.3 零钱通收益2.4 零钱通消费2.5 零钱通退出确认2.6 零钱通金额校验2.7 完整代码 三、零钱通OOP版 前言 本文是我跟着B站韩顺平老师的 Java 教程学习时动手实现“零钱通”项目的学习笔记&#xff0c;主要…

人工智能数学基础实验(四):最大似然估计的-AI 模型训练与参数优化

一、实验目的 理解最大似然估计&#xff08;MLE&#xff09;原理&#xff1a;掌握通过最大化数据出现概率估计模型参数的核心思想。实现 MLE 与 AI 模型结合&#xff1a;使用 MLE 手动估计朴素贝叶斯模型参数&#xff0c;并与 Scikit-learn 内置模型对比&#xff0c;深入理解参…

我的第1个爬虫程序——豆瓣Top250爬虫的详细步骤指南

我的第1个爬虫程序——豆瓣Top250爬虫的详细步骤指南 一、创建隔离开发环境 1. 使用虚拟环境&#xff08;推荐venv&#xff09; # 在项目目录打开终端执行 python -m venv douban_env # 创建虚拟环境 source douban_env/bin/activate # Linux/macOS激活 douban_env\Scri…

STM32八股【11】-----Linux Bootloader (U-Boot)

参考U-Boot U-Boot是什么 嵌入式Linux系统需要一个bootloader来加载系统 U-boot就是一个通用开源的嵌入式Linux bootloader 主要实现的功能&#xff1a; 初始化硬件资源&#xff08;如内存、串口、存储器等&#xff09;从存储介质加载Linux内核到内存中传递启动参数给内核启…

【设计模式】责任链+模板+工程模式使用模板

前言 方便写出优雅&#xff0c;解耦&#xff0c;高内聚&#xff0c;高复用的代码。 Demo // 1. 定义验证器接口&#xff08;责任链模式&#xff09; public interface Validator {Validator setNext(Validator next);boolean validate(Data data); }// 2. 创建抽象验证器&am…

Unity3D仿星露谷物语开发49之创建云杉树

1、目标 创建一颗既可以生长又可以砍伐的云杉树&#xff0c;这个和之前创建橡树类似。 2、创建云杉树预制体 创建新物体命名为CropTreeBlueSpruce&#xff0c;并且添加Box Collider 2D和Crop组件。 在CropTreeBlueSpruce下创建子物体命名为CropSprite&#xff0c;添加3个组件…

【C#】消息队列的使用

在C#中使用消息队列&#xff0c;通常是指使用微软的Message Queuing (MSMQ)技术。MSMQ提供了一种异步通信协议&#xff0c;允许应用程序通过暂时存储要发送到目的地的消息来相互通信。 安装MSMQ 首先&#xff0c;确保你的开发机器和部署服务器上都安装了MSMQ。可以通过“控制…

IP-guard发布新版本4.87.2241.0

IP-guard发布新版本4.87.2241.0 新版本下载地址: https://www.tec-development.com/down/IPguard/Release/V4/IPguard4.87.2241.0.zip?s=901D45ADB22CBBFE5C612DC40AFD6BFB1551A9CD54EF418D5E86BBD256813867 新版本升级地址:

【Linux 服务器磁盘映像备份与恢复实战指南】虚拟机备份,物理机上云都可以用这套方案!

Linux 服务器磁盘映像备份与恢复实战指南 背景 在服务器运维中&#xff0c;磁盘健康度下降可能导致数据丢失风险&#xff0c;特别是在未配置 RAID 的情况下。针对这种情况&#xff0c;备份磁盘数据并恢复到新设备是确保数据安全的关键。本文记录了使用 dd 命令通过 NFS 实现全…

深入理解 Linux 的 set、env 和 printenv 命令

在 Linux 和类 Unix 系统中&#xff0c;环境变量是配置和管理 Shell 及进程行为的核心机制。set、env 和 printenv 是与环境变量交互的三个重要命令&#xff0c;每个命令都有其独特的功能和用途。本文将详细探讨这三个命令的区别&#xff0c;帮助大家更好地理解和使用这些命令。…

icexmoon-tree

icexmoon-tree 一个轻量级的 Java 工具库&#xff0c;提供树形结构操作功能。 安装 <dependency><groupId>cn.icexmoon</groupId><artifactId>icexmoon-tree</artifactId><version>1.0.0</version> </dependency>使用 构建…

机器学习在智能水泥基复合材料中的应用与实践

“机器学习在智能水泥基复合材料中的应用与实践” 课程 内容 机器学习基础模型与复合材料研究融合 机器学习在复合材料中的应用概述机器学习用于复合材料研究的流程复合材料数据收集与数据预处理 实例&#xff1a;数据的收集和预处理 复合材料机器学习特征工程与选择 实例&a…

微软 Build 2025:开启 AI 智能体时代的产业革命

在 2025 年 5 月 19 日的微软 Build 开发者大会上&#xff0c;萨提亚・纳德拉以 "我们已进入 AI 智能体时代" 的宣言&#xff0c;正式拉开了人工智能发展的新纪元。这场汇聚了奥特曼、黄仁勋、马斯克三位科技领袖的盛会&#xff0c;不仅发布了 50 余项创新产品&#…

[Java恶补day6] 15. 三数之和

给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 示例 1&a…

《黄帝内经》数学建模与形式化表征方式的重构

黄帝内经的数学概括&#xff1a;《黄帝内经》数学建模与形式化表征方式的重构 摘要&#xff1a;《黄帝内经》通过现代数学理论如动力系统、代数拓扑和随机过程&#xff0c;被重构为一个形式化的人体健康模型。该模型包括阴阳动力学的微分几何、五行代数的李群结构、经络拓扑与同…