C++原子类型操作与内存序详解

这段内容深入介绍了C++标准原子类型的操作接口、内存序语义及使用规范。以下是关键知识点的分层解析:

一、原子类型的命名规则与类型映射

C++提供两种方式表示原子类型:

  1. 模板特化形式std::atomic<T>
  2. 别名形式atomic_前缀 + 类型名(内置类型有缩写规则)

类型映射表

基础类型原子类型(模板特化)原子类型(别名)
intstd::atomic<int>atomic_int
unsignedstd::atomic<unsigned>atomic_uint
long longstd::atomic<long long>atomic_llong
void*std::atomic<void*>atomic_pointer

最佳实践:优先使用std::atomic<T>,避免因编译器差异导致的兼容性问题。

二、原子类型的操作限制与接口设计

1. 禁用拷贝语义

原子类型不支持拷贝构造和拷贝赋值,防止数据竞争:

std::atomic<int> a(42);
// std::atomic<int> b(a);  // 错误:拷贝构造被删除
// b = a;                  // 错误:拷贝赋值被删除
2. 核心操作分类
  • 存储操作store()、赋值运算符(=
  • 加载操作load()、隐式类型转换
  • 读-改-写操作(RMW)fetch_add()exchange()compare_exchange_weak/strong()
3. 操作返回值设计
  • 赋值运算符返回存储的值
  • 命名函数(如fetch_add())返回操作前的值

示例对比

std::atomic<int> x(10);
int a = x.fetch_add(5);  // a = 10(操作前的值),x = 15
int b = (x += 5);        // b = 20(存储的值),x = 20

三、用户自定义类型的原子支持

std::atomic主模板可用于用户自定义类型,但需满足:

  1. 类型必须是Trivially Copyable(即有平凡拷贝构造/赋值、析构函数)
  2. 操作仅限于:load()store()exchange()compare_exchange_*

示例

struct Point {int x, y;
};  // 满足Trivially Copyablestd::atomic<Point> atomic_point;
Point p = {1, 2};
atomic_point.store(p);

四、内存序的分类与适用场景

内存序控制原子操作的同步强度,影响编译器和CPU的指令重排:

1. 六大内存序值
内存序适用操作同步强度典型场景
memory_order_relaxed所有操作最弱(仅保证原子性)计数器自增(无需同步顺序)
memory_order_release存储操作释放语义发布数据(配合acquire使用)
memory_order_acquire加载操作获取语义获取由release发布的数据
memory_order_consume加载操作弱获取(已弃用)基于依赖关系的同步
memory_order_acq_relRMW操作同时具备acquire/release实现锁(如compare_exchange)
memory_order_seq_cst所有操作最强(全序)默认值,简化同步推理
2. 内存序组合示例
std::atomic<bool> ready(false);
std::atomic<int> data(0);// 线程1:发布数据
data.store(42, std::memory_order_relaxed);
ready.store(true, std::memory_order_release);  // 释放屏障// 线程2:获取数据
while (!ready.load(std::memory_order_acquire));  // 获取屏障
int value = data.load(std::memory_order_relaxed);  // 保证读到42

五、原子操作的默认行为

若未显式指定内存序,原子操作默认使用memory_order_seq_cst(顺序一致性):

  • 所有线程观察到的操作顺序完全一致
  • 相当于所有操作都有全序关系
  • 性能开销最高,但简化了同步推理

示例

std::atomic<int> x(0), y(0);// 线程1
x.store(1);  // 默认memory_order_seq_cst// 线程2
y.store(1);  // 默认memory_order_seq_cst// 线程3
while (x.load() == 0);
if (y.load() == 0) { /* 此处永远不会执行 */ }

六、性能优化建议

  1. 避免过度同步

    • 对无顺序要求的操作(如计数器)使用memory_order_relaxed
    • 示例:
      std::atomic<int> counter(0);
      counter.fetch_add(1, std::memory_order_relaxed);  // 仅保证原子性
      
  2. 使用release/acquire对

    • 在生产者-消费者模型中,生产者使用release,消费者使用acquire
    • 示例:
      // 生产者线程
      buffer = prepare_data();
      ready.store(true, std::memory_order_release);// 消费者线程
      while (!ready.load(std::memory_order_acquire));
      process(buffer);
      
  3. 谨慎使用seq_cst

    • 仅在需要全局顺序保证时使用
    • 多数场景可通过release/acquire实现相同逻辑,性能更优

七、总结:原子操作的核心价值

  1. 提供轻量级同步:通过硬件指令避免锁的开销
  2. 精确控制内存序:在性能和正确性间取得平衡
  3. 支持用户自定义类型:扩展原子操作的应用范围

理解原子操作的接口设计和内存序语义,是编写高性能并发代码的关键。在实际应用中,应优先使用std::atomic模板特化,并根据场景选择合适的内存序,避免不必要的同步开销。

C++原子类型操作全解析:分类、实例与应用场景

C++原子类型提供了丰富的操作接口,按功能可分为基础操作、算术操作、位操作和CAS操作四大类。不同操作适用于不同的并发场景,合理选择能显著提升程序性能与安全性。

一、基础操作:加载、存储与交换

1. 核心接口
操作类型函数名称运算符重载说明
存储(Store)store(T value)atomic_var = value原子写入值,可选内存序
加载(Load)load()(T)atomic_var原子读取值,可选内存序
交换(Exchange)exchange(T desired)原子替换值并返回旧值,可选内存序
2. 典型应用场景
  • 线程间标志传递:使用store/release发布数据,load/acquire获取数据
    std::atomic<bool> ready(false);// 生产者线程
    void producer() {data = prepare();ready.store(true, std::memory_order_release);
    }// 消费者线程
    void consumer() {while (!ready.load(std::memory_order_acquire));process(data);
    }
    
  • 实现无锁单例模式:使用exchange原子初始化指针
    std::atomic<Singleton*> instance(nullptr);Singleton* getInstance() {Singleton* tmp = instance.load();if (!tmp) {tmp = new Singleton();if (!instance.exchange(tmp)) {delete tmp;tmp = instance.load();}}return tmp;
    }
    

二、算术操作:原子增减与复合赋值

1. 核心接口
操作类型函数名称运算符重载说明
加法fetch_add(T value)+=原子加并返回旧值,适用于整数/指针
减法fetch_sub(T value)-=原子减并返回旧值,适用于整数/指针
前置/后置自增++atomic_varatomic_var++原子自增,返回新值/旧值
前置/后置自减--atomic_varatomic_var--原子自减,返回新值/旧值
2. 典型应用场景
  • 高性能计数器:使用fetch_add实现无锁计数
    std::atomic<int> counter(0);void worker() {for (int i = 0; i < 1000; ++i) {counter.fetch_add(1, std::memory_order_relaxed);}
    }
    
  • 资源引用计数:使用fetch_sub实现原子释放资源
    struct Resource {std::atomic<int> ref_count{1};void add_ref() { ref_count.fetch_add(1); }void release() {if (ref_count.fetch_sub(1) == 1) {delete this;}}
    };
    

三、位操作:原子按位运算

1. 核心接口
操作类型函数名称运算符重载说明
按位或fetch_or(T value)`=`
按位与fetch_and(T value)&=原子按位与并返回旧值
按位异或fetch_xor(T value)^=原子按位异或并返回旧值
2. 典型应用场景
  • 标志位管理:使用fetch_orfetch_and原子设置/清除标志
    enum Flags {INITIALIZED = 1 << 0,CONNECTED = 1 << 1,READY = 1 << 2
    };std::atomic<int> status(0);// 设置INITIALIZED标志
    status.fetch_or(INITIALIZED, std::memory_order_relaxed);// 清除CONNECTED标志
    status.fetch_and(~CONNECTED, std::memory_order_relaxed);
    
  • 并发位图(BitSet):使用原子位操作实现线程安全位图
    class AtomicBitSet {std::atomic<uint64_t> bits{0};public:bool test_and_set(size_t pos) {uint64_t mask = 1ULL << pos;return bits.fetch_or(mask) & mask;}
    };
    

四、CAS操作:比较并交换

1. 核心接口
函数名称说明
compare_exchange_weak(T& expected, T desired)弱CAS,可能因硬件原因失败,需循环重试
compare_exchange_strong(T& expected, T desired)强CAS,保证一次成功或失败
2. 典型应用场景
  • 实现无锁栈:使用CAS原子更新栈顶指针
    template<typename T>
    class LockFreeStack {struct Node { T data; Node* next; };std::atomic<Node*> head{nullptr};public:void push(const T& value) {Node* new_node = new Node{value, head.load()};while (!head.compare_exchange_weak(new_node->next, new_node));}
    };
    
  • 原子累加器:使用CAS实现更高效的累加(比fetch_add减少缓存争用)
    class AtomicAccumulator {std::atomic<int> value{0};public:void add(int delta) {int expected = value.load();while (!value.compare_exchange_weak(expected, expected + delta));}
    };
    

五、操作选择决策树

是否需要原子读写?
│
├── 是 → 是否只需存储/加载?
│   │
│   ├── 是 → 使用 store()/load() 或赋值/类型转换
│   │
│   ├── 否 → 是否需要原子替换值?
│       │
│       ├── 是 → 使用 exchange()
│       │
│       ├── 否 → 是否需要原子比较并替换?
│           │
│           ├── 是 → 使用 compare_exchange_weak/strong()
│           │
│           ├── 否 → 是否为整数或指针类型?
│               │
│               ├── 是 → 是否需要算术操作?
│               │   │
│               │   ├── 是 → 使用 fetch_add()/fetch_sub() 或 +=/-=
│               │   │
│               │   ├── 否 → 是否需要位操作?
│               │       │
│               │       ├── 是 → 使用 fetch_or()/fetch_and() 等
│               │       │
│               │       └── 否 → 无匹配操作
│               │
│               └── 否 → 无匹配操作(仅支持基本原子操作)
│
└── 否 → 使用普通变量

六、性能优化建议

  1. 优先使用无锁操作

    • 对简单计数使用fetch_add替代互斥锁
    • 示例:counter.fetch_add(1, std::memory_order_relaxed)
  2. 合理选择CAS类型

    • 循环次数较多时使用compare_exchange_strong
    • 性能敏感场景使用compare_exchange_weak并循环重试
  3. 内存序优化

    • 无顺序要求的操作使用memory_order_relaxed
    • 发布-订阅模型使用memory_order_release/acquire
  4. 避免伪共享(False Sharing)

    • 使用alignas确保原子变量对齐到缓存行
    struct alignas(64) Counters {std::atomic<int> counter1{0};std::atomic<int> counter2{0};  // 与counter1分开在不同缓存行
    };
    

七、总结:操作与场景映射表

操作类型核心函数典型应用场景
存储/加载store(), load()线程间标志传递、状态同步
交换exchange()单例模式初始化、资源所有权转移
算术操作fetch_add(), ++计数器、引用计数、负载均衡
位操作fetch_or(), &=并发位图、标志位管理、状态机实现
CAS操作compare_exchange_*无锁数据结构(栈、队列)、原子累加器、复杂状态更新

理解原子操作的分类和适用场景,是编写高性能并发代码的关键。在实际应用中,应根据操作的原子性需求、性能要求和同步语义,选择最合适的原子操作类型和内存序。

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

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

相关文章

互联网摸鱼日报(2025-07-07)

互联网摸鱼日报(2025-07-07) 钛媒体 一场突如其来的“召回潮”&#xff0c;点燃中国制造的“灵魂拷问” 史上最大外卖补贴战开打&#xff0c;美团聚拢资源迎战“巨无霸” 1315亿加冕潮汕女首富&#xff0c;“最强打工妹”剑指港股 用14346字&#xff0c;讲透上市前必做的10…

七牛云Java开发面试题及参考答案

详述 Java 方法重载的机制与应用场景 Java 方法重载&#xff08;Method Overloading&#xff09;是面向对象编程中的重要特性&#xff0c;它允许同一个类中存在多个同名但参数列表不同的方法。这种机制为代码提供了灵活性和可读性&#xff0c;使得开发者可以用统一的方法名处理…

.net core mvc部署到win10本地的Ubuntu上

将一个 .NET Core MVC 应用部署到 Windows 10 上通过 WSL 安装的 Ubuntu 环境中&#xff0c;可以分为几个步骤来完成。以下是详细的指南&#xff1a;准备工作确保你的Ubuntu环境已安装.NET SDK&#xff1a;首先&#xff0c;你需要在WSL中的Ubuntu上安装.NET SDK。可以通过以下命…

机器人VLA模型(Vision-Language-Action)

一、VLA模型的技术架构与核心原理 VLA&#xff08;Vision-Language-Action&#xff09;模型的核心是构建视觉、语言、动作的多模态闭环系统&#xff0c;实现从感知到执行的端到端映射。其技术架构可细分为四个关键模块&#xff1a; 1. 多模态编码器 视觉编码器&#xff1a; …

单点登录SSO的演进和最佳实践,含springBoot 实现(Java版本)

一、单点登录&#xff08;SSO&#xff09;概述 单点登录&#xff08;SSO, Single Sign-On&#xff09;是一种认证机制&#xff0c;允许用户只需登录一次&#xff0c;即可访问多个相互信任的系统或应用&#xff0c;而不需要为每个系统重复登录。 二、SSO 演进路径 我们可以从以…

Python----OpenCV(图像増强——高通滤波(索贝尔算子、沙尔算子、拉普拉斯算子),图像浮雕与特效处理)

一、 高通滤波 高通滤波是对图像进行卷积操作&#xff0c;以保留图像中的快速变化部分&#xff08;如边缘和细节&#xff09;&#xff0c;同时抑 制低频分量&#xff08;如大面积平坦区域&#xff09;。 应用场景 边缘检测&#xff1a;提取物体轮廓和边界。特征提取&#xff…

oracle 恢复

RECOVER DATABASE USING BACKUP CONTROLFILE “用备份的控制文件推动数据库恢复”。-- 检查控制文件记录的当前SCN (V$DATABASE) SELECT CURRENT_SCN FROM V$DATABASE; -- 检查数据文件头SCN (V$DATAFILE_HEADER) SELECT FILE#, CHECKPOINT_CHANGE# FROM V$DATAFILE_HEADER;-…

京东商品详情SKU数据采集的难点有哪些?

京东商品详情 SKU 数据采集过程中&#xff0c;由于平台的技术防护、数据结构特性及合规性要求&#xff0c;会面临诸多难点&#xff0c;具体如下&#xff1a;一、反爬虫机制的限制京东作为大型电商平台&#xff0c;拥有成熟且严格的反爬虫系统&#xff0c;这是采集时最核心的障碍…

修复手机液晶面板显性横向线性不良定位及相关液晶线路激光修复原理

摘要 手机液晶面板显性横向线性不良严重影响屏幕显示效果&#xff0c;其产生与液晶线路断路、短路或信号传输异常密切相关。精准定位线性不良区域是修复的关键前提&#xff0c;激光修复技术凭借高能量密度与非接触特性&#xff0c;能够有效修复相关液晶线路故障。本文分析显性…

如何解决Spring Boot中@Valid对List校验失效问题

在Spring Boot应用开发中&#xff0c;我们经常需要对传入的请求参数进行校验&#xff0c;以确保数据的合法性和安全性。然而&#xff0c;当我们尝试对列表&#xff08;List&#xff09;类型的参数进行校验时&#xff0c;可能会遇到校验失效的问题。本文将详细探讨这一问题的失效…

云原生环境下部署大语言模型服务:以 DeepSeek 为例的实战教程

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、引言 随着 DeepSeek、Qwen、ChatGLM 等大语言模型&#xff08;LLM&#xff09;的开放与普及&#xff0c;企业将其私有化部署…

【Spring篇08】:理解自动装配,从spring.factories到.imports剖析

文章目录1. 自动化装配的起点&#xff1a;SpringBootApplication2. 自动化装配的核心机制&#xff1a;EnableAutoConfiguration 和 AutoConfigurationImportSelector3. 自动化配置的注册方式&#xff1a;spring.factories 与 .imports3.1 早期版本&#xff1a;META-INF/spring.…

前置代理重构网络访问的「中转站」

某跨境电商通过前置代理构建账号隔离体系&#xff0c;将亚马逊店铺关联风险降低85%&#xff1b;某企业利用前置代理过滤恶意流量&#xff0c;网络攻击拦截率提升70%。在复杂的网络环境中&#xff0c;前置代理作为客户端与目标服务器之间的「中间枢纽」&#xff0c;正成为跨境访…

乐鑫代理商飞睿科技,2025年AI智能语音助手市场发展趋势与乐鑫芯片解决方案分析

一、市场现状与技术背景进入2025年&#xff0c;AI智能语音助手市场呈现出爆发性增长态势。全球AI应用访问量从2024年初的36亿次激增至76亿次&#xff0c;增幅高达111%&#xff0c;其中语音交互类产品贡献了显著份额。在企业市场&#xff0c;语音技术已从“增值服务”转变为不可…

App爬虫工具篇-Appium安装

之前在另外一篇文章App爬虫工具篇-mitmproxy简单介绍了利用mitmproxy进行接口拦截来获取接口数据。但是很多软件现在都会对相关接口进行加密。如以下我用mitmproxy拦截到接口流量样例: {"raw_data": "EXMcAezXPq/MRC1m2mJIG/EQLisaahfpjPTj9svrxe6yLI8mZTvW4+…

容器与 Kubernetes 基本概念与架构

文章目录 1. 典型环境层次结构2. Kubernetes 生态三大类2.1 核心组件2.2 集群管理工具2.3 生态辅助工具2.4 资源管理关系 3. Docker 容器技术与实践3.1 镜像拉取加速3.2 认证与登录3.3 常用命令3.4 存储挂载方式对比3.5 docker-compose 启动3.6 容器化应用部署示例 4. kind 快速…

Ajax和Axios的初步学习

Ajax 一、什么是 Ajax&#xff1f; Ajax (Asynchronous JavaScript and XML) 是一种无需重新加载整个网页的情况下&#xff0c;能够更新部分网页的技术。通过在后台与服务器进行少量数据交换&#xff0c;Ajax 可以使网页实现异步更新。 主要特性&#xff1a; 异步性 (Asynch…

C#指针:解锁内存操作的底层密码

C#指针&#xff1a;解锁内存操作的底层密码 在 C# 的世界里&#xff0c;我们习惯了托管代码带来的安全与便捷 —— 垃圾回收器自动管理内存&#xff0c;类型系统严格检查数据操作&#xff0c;就像在精心维护的花园中漫步&#xff0c;无需担心杂草与荆棘。但当性能成为关键瓶颈…

永洪科技荣获商业智能品牌影响力奖,全力打造”AI+决策”引擎

近日&#xff0c;在备受业界瞩目的年度商业智能领域权威评选中&#xff0c;永洪科技凭借卓越的技术实力、深度的客户价值创造能力与前瞻的行业洞察&#xff0c;成功斩获“2025商业智能品牌影响力奖”。这一奖项不仅是对永洪科技市场地位与品牌声量的高度认可&#xff0c;更是对…

在SSM+vue项目中上传表单数据和文件

从前端向后端发送multipart/form-data 类型数据&#xff08;主要用于文件上传或表单提交&#xff09;如发送如下信息&#xff1a;前端代码vue文件&#xff1a;&#xff08;配置了服务器代理&#xff09;<template><div class"content"><el-form :mode…