C++中的原子操作:原子性、内存顺序、性能优化与原子变量赋值
一、原子操作与原子性
原子操作(atomic operation)是并发编程中的一个核心概念,指的是在多线程环境中,一个操作一旦开始,就不会被其他线程的操作打断,直至该操作完成。这种不可分割的特性保证了操作的原子性,即要么全部做完,要么全部不做。原子操作在多线程编程中非常重要,因为它能有效避免数据竞争和条件竞争等问题,从而确保程序的正确性和稳定性。
C++11引入了原子操作,通过<atomic>
头文件提供了一系列原子类型和函数,如std::atomic<T>
,用于确保对共享数据的操作是原子的。原子类型提供了一系列成员函数来执行原子操作,这些操作包括加载(load)、存储(store)、加法(fetch_add、add)、减法(fetch_sub、sub)、交换(exchange)和比较并交换(compare_exchange_weak、compare_exchange_strong)等。
二、原子变量赋值操作
在C++中,原子变量赋值是通过std::atomic
模板类实现的,提供了多种方法来对原子变量进行赋值和修改。以下是一些常见的原子变量赋值操作及其示例:
-
基本赋值
基本赋值操作是使用赋值运算符(=)直接将一个新值赋给原子变量。例如:
std::atomic<int> counter(0); // 声明一个原子整数变量,初始值为0
counter = 10; // 将10赋给counter
-
原子加法与减法
使用
fetch_add
、add
等成员函数可以实现原子加法操作,fetch_sub
、sub
等成员函数可以实现原子减法操作。fetch_add
和fetch_sub
返回加法或减法操作之前的值,而add
和sub
返回加法或减法操作之后的值。例如:
std::atomic<int> counter(0);int oldValue = counter.fetch_add(1); // 将counter的值加1,并返回加1之前的值int newValue = counter.add(5); // 将counter的值加5,并返回加5之后的值oldValue = counter.fetch_sub(3); // 将counter的值减3,并返回减3之前的值newValue = counter.sub(2); // 将counter的值减2,并返回减2之后的值
-
原子交换
使用
exchange
成员函数可以实现原子交换操作,即将原子变量的当前值与一个新值进行交换,并返回交换之前的值。例如:
std::atomic<int> counter(5);
int oldValue = counter.exchange(10); // 将counter的值与10进行交换,并返回交换之前的值5
-
原子比较并交换
使用
compare_exchange_weak
或compare_exchange_strong
成员函数可以实现原子比较并交换操作。这两个函数都尝试将原子变量的当前值与一个期望值进行比较,如果相等,则将其设置为一个新值,并返回true;如果不相等,则返回false,并将期望值更新为当前值。compare_exchange_weak
在某些平台上可能会由于性能优化而偶尔失败(即使当前值与期望值相等),而compare_exchange_strong
则保证在当前值与期望值相等时一定会成功。例如:
std::atomic<int> counter(5);int expected = 5;bool success = counter.compare_exchange_strong(expected, 10); // 如果counter的值等于5,则将其设置为10,并返回true;否则返回false,并将expected更新为counter的当前值
- 原子性值传递
有时,我们需要将一个原子变量的值从一个对象复制到另一个对象。这可以通过load()
和store()
成员函数来实现。load()
函数用于从原子变量中加载当前值,而store()
函数用于将一个新值存储到原子变量中。以下是一个示例:
std::atomic<int> original(5); // 声明一个原子整数变量,初始值为5
std::atomic<int> target(0); // 声明另一个原子整数变量,初始值为0// 将original的值加载到局部变量中(虽然在这个例子中不是必需的,但展示了load的用法)
int value = original.load();// 直接将original的值存储到target中,这是一个原子操作
target.store(original.load()); // 将原始对象的值存储到目标对象// 此时,target的值也是5
三、内存顺序
内存顺序(Memory Order)是多线程编程中一个非常重要的概念,它定义了在多处理器或多核环境中,内存访问的次序。C++11标准明确引入了内存顺序,用于指定原子操作的顺序性,以避免多线程环境下的数据竞争问题。
C++11标准定义了多种内存顺序类型,包括memory_order_relaxed
、memory_order_consume
、memory_order_acquire
、memory_order_release
、memory_order_acq_rel
和memory_order_seq_cst
等。在实际编程中,开发者需要根据操作的目的和上下文环境来确定合适的内存顺序。
选择合适的内存顺序可以在保证正确性的前提下提高性能。例如,使用memory_order_relaxed
可以放松对内存顺序的要求,从而减少同步开销,但可能会引入数据竞争的风险。相反,使用memory_order_seq_cst
可以确保最强的顺序性保证,但可能会增加同步开销。
四、性能优化
原子操作通过避免锁的使用,减少了线程之间的竞争和上下文切换开销,从而提高了多线程程序的性能。然而,性能优化并非一味追求宽松的内存顺序,而需要在正确性和性能之间取得平衡。
以下是一些性能优化的建议:
-
选择合适的内存顺序:在保证线程安全的前提下,尽量使用宽松的内存顺序可以减少同步操作,从而提升性能。然而,过度放宽内存顺序可能会导致难以调试的并发问题。
-
利用硬件特性:不同CPU架构和编译器的实现对原子操作的支持和优化程度不同。深入理解平台特性,利用硬件提供的原子性支持和缓存一致性机制,可以进一步提高程序的性能。
-
减少不必要的同步:通过合理设计算法和数据结构,减少线程间的同步需求。例如,使用无锁数据结构、读写锁等高级同步机制,可以在保持线程安全的同时,减少同步开销。
-
避免忙等待:在需要等待某个条件成立时,避免使用忙等待(busy-waiting)的方式。忙等待会消耗大量的CPU资源,并可能导致性能下降。相反,可以使用条件变量、信号量等同步机制来实现高效的等待和通知机制。
综上所述,深入理解C++中的原子操作、原子性、内存顺序、性能优化以及原子变量赋值操作,对于编写高效且正确的并发代码至关重要。通过合理选择内存顺序、利用硬件特性、减少不必要的同步和避免忙等待等策略,可以在保证程序正确性的同时实现性能的优化。
相关文章:
C++中的原子操作:原子性、内存顺序、性能优化与原子变量赋值
一、原子操作与原子性 原子操作(atomic operation)是并发编程中的一个核心概念,指的是在多线程环境中,一个操作一旦开始,就不会被其他线程的操作打断,直至该操作完成。这种不可分割的特性保证了操作的原子…...

游戏引擎学习第19天
介绍 这段内容描述了开发者在进行游戏开发时,对于音频同步和平台层的理解和调整的过程。以下是更详细的复述: 开发者表达了他希望今天继续进行的工作内容。他提到,昨天他讲解了一些关于音频的内容,今天他想稍微深入讲解一下他正…...
RocketMQ: 专业术语以及相关问题解决
概述 要了解 RocketMQ 的多个关键特性的实现原理,并对消息中间件遇到的各种问题进行解决我们引用 JMS 规范 与 CORBA Notification 规范,规范为我们设计系统指明了方向但是仍有不少问题规范没有提及,对于消息中间件又至关重要RocketMQ 并不遵…...

C++ 类和对象中的 拷贝构造 和 运算符重载
构造函数中可以添加参数并添加默认值构成缺省构造,如果我们在构造函数的参数中加上自身类型类的引用和其他给出默认值的参数则会构成一种特殊的构造函数叫做———拷贝构造函数 1.拷贝构造 拷贝构造的特点: 1.拷贝构造函数是构造函数的一个重载 2.拷…...
el-table最大高度无法滚动
解决el-table同时使用fixed和计算的最大高度时固定右边的列无法跟随滚动的问题 原因:el-table组件会根据传入的 max-height 计算表格内容部分 和 fixed部分的最大高度,以此来生成滚动条和产生滚动效果,当传入的 max-height 为一个计算的高度…...

Vscode写markdown快速插入python代码
如图当我按下快捷键CRTLSHIFTK 自动出现python代码片段 配置方法shortcuts’ 打开这个json文件 输入 {"key": "ctrlshiftk","command": "editor.action.insertSnippet","when": "editorTextFocus","args&…...

基于 NCD 与优化函数结合的非线性优化 PID 控制
基于 NCD 与优化函数结合的非线性优化 PID 控制 1. 引言 NCD(Normalized Coprime Factorization Distance)优化是一种用于非线性系统的先进控制方法。通过将 NCD 指标与优化算法结合,可以在动态调整控制参数的同时优化控制器性能。此方法特别…...
【数据分析】基于GEE实现大津算法提取洞庭湖流域水体
大津算法提取水体 1.写在前面2.洞庭湖水体识别1.写在前面 最大类间方差法,也称为Otsu或大津法,是一种高效的图像二值化算法,由日本学者Otsu于1979年提出。该算法基于图像的频率分布直方图,假设图像包含两类像素(前景和背景),并计算出一个最佳阈值,以最大化类间方差,从…...

计算机网络安全 —— 报文摘要算法 MD5
一、报文摘要算法基本概念 使用加密通常可达到报文鉴别的目的,因为伪造的报文解密后一般不能得到可理解的内容。但简单采用这种方法,计算机很难自动识别报文是否被篡改。另外,对于不需要保密而只需要报文鉴别的网络应用,对整个…...
LeetCode 746. 使用最小花费爬楼梯 java题解
https://leetcode.cn/problems/min-cost-climbing-stairs/description/ 优化:可以不用dp数组,用变量,节省空间。 class Solution {public int minCostClimbingStairs(int[] cost) {int lencost.length;int[] dpnew int[len1];dp[0]0;//爬到0…...

Kubernetes的pod控制器
文章目录 一,什么是pod控制器二,pod控制器类型(重点)1.ReplicaSet2.Deployment3.DaemonSet4.StatefulSet5.Job6.Cronjob 三,pod与控制器的关系1.Deployment2.SatefulSet2.1StatefulSet组成2.2headless的由来2.3有状态服…...

ArcMap 处理栅格数据地形图配准操作
ArcMap 处理栅格数据地形图配准操作今天分享 一、地形图配准 1、绘图 点击 开始绘制,四条线 2、地理配准 1)点击弹出 2)画控制点 关闭自动校正 画线 从焦点向外划线,然后邮件输入坐标弹出框,填写相应内容,…...
comprehension
1.读题---猜---文章主题 只读题目,不读选项 2.文章--定位 3.用文章对应选项 1 be based on be dependent upon 2 fruitful adj.富有成效的;硕果累累的; 3 unfruitful adj.徒然的,无益的,没有结果的 4 desperately adv.拼命地&#x…...
开源宝藏:Smart-Admin 重复提交防护的 AOP 切面实现详解
首先,说下重复提交问题,基本上解决方案,核心都是根据URL、参数、token等,有一个唯一值检验是否重复提交。 而下面这个是根据用户id,唯一值进行判定,使用两种缓存方式,redis和caffeineÿ…...
使用 npm 安装 Electron 作为开发依赖
好的,下面是一个使用 npm pack 和 npm install 命令来打包和安装离线版本的 npm 包的具体示例。我们将以 electron 为例,演示如何在有网络连接的机器上打包 electron,然后在没有网络连接的机器上安装它。 步骤 1: 在有网络连接的机器上打包 …...

JavaWeb之综合案例
前言 这一节讲一个案例 1. 环境搭建 然后就是把这些数据全部用到sql语句中执行 2.查询所有-后台&前台 我们先写后台代码 2.1 后台 2.2 Dao BrandMapper: 注意因为数据库里面的名称是下划线分割的,我们类里面是驼峰的,所以要映射 …...
MySQL 报错:1137 - Can‘t reopen table
MySQL 报错:1137 - Can’t reopen table 1. 问题 对临时表查询: select a.ts_code,a.tsnum,b.tsnum from (select t.ts_code ,count(*) tsnum from tmp_table t group by t.ts_code having count(*) > 20 and count(*)< 50 ) a ,(select t.ts_…...

Claude3.5-Sonnet和GPT-4o怎么选(附使用链接)
随着人工智能模型的不断进化,传统的评估标准已经逐渐变得陈旧和不再适用。以经典的“喝水测试”为例,过去广泛应用于检测模型能力,但现如今即便是国内的一些先进模型,也能够轻松答对这些简单的问题。因此,我们亟需引入…...

使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
在网上找了很多种办法 都解决不了; 最后发现是文本域字体设置出了问题; 在这不展示其他的代码 只展示重要代码; 1 引入扩展包 <dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</v…...

java-贪心算法
1. 霍夫曼编码(Huffman Coding) 描述: 霍夫曼编码是一种使用变长编码表对数据进行编码的算法,由David A. Huffman在1952年发明。它是一种贪心算法,用于数据压缩。霍夫曼编码通过构建一个二叉树(霍夫曼树&a…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...

解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...