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

C++ 原子变量

C++ 原子变量

文章目录

  • C++ 原子变量
    • 1. 原子变量是什么?
    • 2. 原子操作的特点
    • 3. 原子变量的作用
      • 1. 多线程安全的共享数据访问
      • 2. 替代锁机制
      • 3. 实现低级同步算法
    • 4. 原子变量的常见操作
    • 5. 内存顺序(Memory Ordering)
      • 内存顺序控制在原子变量中的作用
      • 如何影响程序行为
    • 6. 示例:比较并交换(CAS)
    • 7. 总结

在 C++11 中,原子变量(atomic variables)是指通过 std::atomic 类型封装的变量,它们的操作在多线程环境中是 原子的,即不可分割的。这意味着对原子变量的操作(如读取、写入、更新等)是线程安全的,不会被其他线程的操作干扰或中断。

1. 原子变量是什么?

原子变量是 C++11 引入的,用于在多线程程序中确保对共享数据的访问是安全的。使用 std::atomic 类型,可以对变量进行原子操作,从而避免了传统的锁机制(如互斥锁 std::mutex)的使用。

std::atomic 是一个模板类,支持多种数据类型(如 int, bool, pointer 等)。它保证对该变量的操作是原子的,即所有操作要么完全成功,要么完全失败,不会被中断、重排或与其他线程的操作发生冲突。

2. 原子操作的特点

原子操作有几个显著的特点:

  • 不可分割:原子操作要么完全执行,要么完全不执行,不会被其他线程的操作打断。
  • 线程安全:由于原子性,多个线程可以同时访问同一个原子变量,而无需显式地加锁(如 std::mutex)。这对于提升并发性能非常重要。
  • 避免数据竞争:通过确保每个操作是原子性的,避免了数据竞争(data race)的问题。

3. 原子变量的作用

原子变量在并发编程中起着非常重要的作用,它们的主要用途包括:

1. 多线程安全的共享数据访问

在多线程程序中,多个线程可能会同时访问并修改同一共享数据。使用常规的变量时,可能会发生数据竞争(data race),导致数据不一致或者程序崩溃。而原子变量可以确保对其的操作是原子的,从而避免了数据竞争。

例如,下面的代码演示了如何使用原子变量来安全地进行递增操作:

#include <iostream>
#include <atomic>
#include <thread>std::atomic<int> counter(0);  // 定义一个原子变量void increment() {for (int i = 0; i < 10000; ++i) {counter.fetch_add(1, std::memory_order_relaxed);  // 原子加 1}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "Final counter value: " << counter.load() << std::endl;  // 安全读取原子变量return 0;
}

在上述代码中,两个线程 t1t2 都在对 counter 进行自增操作。由于 counter 是原子变量,这样的操作是线程安全的,避免了数据竞争。

2. 替代锁机制

原子操作通过硬件提供的原子指令,能够高效地完成一些常见的同步任务,例如递增、递减、交换、比较和交换等操作,而不需要使用传统的锁机制(如 std::mutex)。这可以有效减少锁的使用,提高程序的并发性能。

传统的锁机制(如互斥锁)通常会引入线程上下文切换和性能开销,而原子变量的操作是直接通过硬件实现的,通常具有更高的效率。

3. 实现低级同步算法

在一些低级的并发数据结构和算法中,原子变量常常用于实现高效的同步机制,例如无锁队列、栈、哈希表等。通过原子操作,可以避免锁的使用,从而提高并发度和程序的整体性能。

4. 原子变量的常见操作

C++11 中的 std::atomic 提供了多种原子操作,这些操作可以保证对原子变量的修改是线程安全的。常见的操作包括:

  • load(): 读取原子变量的值。
  • store(): 设置原子变量的值。
  • exchange(): 将原子变量的值替换为指定值,并返回原先的值。
  • compare_exchange_weak() / compare_exchange_strong(): 比较并交换(CAS,Compare and Swap)操作,只有当当前值等于预期值时才会交换。
  • fetch_add() / fetch_sub(): 原子地执行加法或减法。
  • fetch_and() / fetch_or() / fetch_xor(): 原子地执行按位与、按位或、按位异或。

例如:

std::atomic<int> value(0);// 原子加法
value.fetch_add(1, std::memory_order_relaxed);// 比较并交换
int expected = 0;
value.compare_exchange_weak(expected, 1);// 读取原子变量
int current_value = value.load();

5. 内存顺序(Memory Ordering)

std::atomic 操作有一个重要的概念——内存顺序。内存顺序控制了操作在多线程程序中的可见性和执行顺序。内存顺序控制决定了在多线程程序中,不同线程间对共享内存的操作顺序。因为现代处理器在执行程序时,可能出于性能考虑进行指令重排和缓存优化,这可能导致不同线程间看到的内存访问顺序不同。

例如,一个线程修改了某个变量的值,另一个线程读取该变量时,可能会看到不同的值,这就是由于内存重排或缓存的原因。为了解决这个问题,可以通过内存顺序控制来指定操作的顺序和可见性,以确保线程之间的同步和数据一致性。

C++11 提供了几种内存顺序选项:

  • memory_order_relaxed: 仅保证原子性,不强制同步顺序。
  • memory_order_consume: 保证当前操作依赖的所有操作在其前面执行。
  • memory_order_acquire: 保证当前操作之前的所有操作不会被重排。
  • memory_order_release: 保证当前操作之后的所有操作不会被重排。
  • memory_order_acq_rel: 同时具有 acquirerelease 的效果。
  • memory_order_seq_cst: 默认的内存顺序,保证所有操作的严格顺序一致。

内存顺序控制在原子变量中的作用

在使用原子变量时,操作不仅仅涉及到对数据的修改,还需要控制操作的可见性(不同线程是否看到相同的值)和顺序性(操作的执行顺序)。

C++11、Java等语言的原子操作库提供了对内存顺序的明确控制,通常有以下几种内存顺序:

  1. 顺序一致性(Sequentially Consistent, memory_order_seq_cst
    • 默认内存顺序。保证所有线程对原子变量的所有操作按照严格的顺序进行,所有线程都能看到一致的执行顺序。这种顺序是最强的同步保证,但也可能牺牲性能。
  2. 获取-释放(Acquire-Release, memory_order_acquirememory_order_release
    • 获取(Acquire):用于确保当前线程在执行某个操作之前,所有前面的操作完成。这通常用于读取原子变量时,确保读取到最新的数据。
    • 释放(Release):用于确保当前线程在执行某个操作之后,所有之后的操作完成。这通常用于写入原子变量时,确保所有更新已被其他线程可见。
    • 获取-释放组合(memory_order_acq_rel):同时包含获取和释放的功能。它常见于涉及原子变量的加减操作,确保操作前后的顺序。
  3. 无序(Unordered, memory_order_relaxed
    • 不对操作的顺序进行约束。线程对原子变量的操作不需要遵循任何内存顺序的规则,这样可以提高性能,但可能导致不同线程看到不一致的内存状态。
  4. 明确顺序(Ordered, memory_order_consumememory_order_acquire
    • memory_order_consume 比较少用,通常被memory_order_acquire替代。其作用是确保之前的数据读取操作先于后续的操作。

如何影响程序行为

通过内存顺序控制,程序员可以精细控制线程间的同步,避免线程间的数据竞争,同时也能够优化程序性能。

  • 内存顺序较弱(如memory_order_relaxed):适用于某些不需要严格同步的场景,可以提高性能,因为它不强制执行指令顺序。
  • 内存顺序较强(如memory_order_seq_cst):适用于需要高度一致性的场景,如多个线程修改共享数据时,需要严格的顺序保证。
#include <atomic>
#include <iostream>
#include <thread>std::atomic<int> data = 0;void producer() {data.store(42, std::memory_order_release);  // Release write
}void consumer() {while (data.load(std::memory_order_acquire) != 42) {  // Acquire readstd::this_thread::sleep_for(std::chrono::milliseconds(10));}std::cout << "Data is: " << data.load() << std::endl;
}int main() {std::thread t1(producer);std::thread t2(consumer);t1.join();t2.join();return 0;
}

在这个示例中,producer线程将数据写入原子变量并使用memory_order_release,而consumer线程在读取时使用memory_order_acquire,这样可以确保consumer线程在读取数据时,所有写入data的操作都已经完成。原子变量的操作通过内存顺序控制来保证多线程程序中的正确性与性能。不同的内存顺序(如acquirereleaseseq_cst等)允许程序员控制操作的同步方式,从而满足不同的并发需求。

6. 示例:比较并交换(CAS)

#include <iostream>
#include <atomic>std::atomic<int> counter(0);bool compare_exchange_example() {int expected = 0;return counter.compare_exchange_weak(expected, 1); // 如果当前值是 0,则将其更改为 1
}int main() {bool success = compare_exchange_example();std::cout << "Exchange success: " << success << ", new counter value: " << counter.load() << std::endl;return 0;
}

7. 总结

原子变量 (std::atomic) 在 C++11 中的引入,主要用于支持多线程程序中的共享数据的安全操作。通过 std::atomic 类型,可以避免使用传统的锁机制来保证线程安全,从而提高程序的并发性和性能。它们的主要用途包括确保多线程环境中共享数据的正确访问,替代锁机制,和在一些低级同步算法中的应用。

相关文章:

C++ 原子变量

C 原子变量 文章目录 C 原子变量1. 原子变量是什么&#xff1f;2. 原子操作的特点3. 原子变量的作用1. 多线程安全的共享数据访问2. 替代锁机制3. 实现低级同步算法 4. 原子变量的常见操作5. 内存顺序&#xff08;Memory Ordering&#xff09;内存顺序控制在原子变量中的作用如…...

linux网络 | http结尾、理解长连接短链接与cookie

前言&#xff1a;本节是http章节的最后一部分&#xff0c;主要解释一些小概念。讲解到了HTTP的方法&#xff0c;表单&#xff0c; 重定向等等。 现在废话不多说&#xff0c; 开始我们的学习吧。 ps&#xff1a;本节内容都是概念&#xff0c; 知道就行&#xff0c; 友友们放心观…...

金融项目实战 02|接口测试分析、设计以及实现

目录 ⼀、接口相关理论 二、接口测试 1、待测接口&#xff1a;投资业务 2、接口测试流程 3、设计用例理论 1️⃣设计方法 2️⃣工具 4、测试点提取 5、测试用例 ⼀、接口相关理论 1、ui功能测试和接⼝测试那个先执⾏&#xff1f;为什么&#xff1f; 结论&#xff1a…...

二、智能体强化学习——深度强化学习核心算法

2.1 DQN 系列及其改进 2.1.1 背景与动机 在经典强化学习中&#xff08;如 Q-Learning&#xff09;&#xff0c;如果状态空间或动作空间非常大乃至连续&#xff0c;那么用一个表格来存储 Q ( s , a ) Q(s,a) Q(s,a) 不再可行。为了解决该问题&#xff0c;可以使用神经网络来逼…...

Mysql--架构篇--存储引擎InnoDB(内存结构,磁盘结构,存储结构,日志管理,锁机制,事务并发控制等)

MySQL是一个多存储引擎的数据库管理系统&#xff0c;支持多种不同的存储引擎。每种存储引擎都有其独特的特性、优势和适用场景。选择合适的存储引擎对于优化数据库性能、确保数据完整性和满足业务需求至关重要。 注&#xff1a;在同一个Mysql的数据库中&#xff0c;对于不同的表…...

JVM实战—13.OOM的生产案例

大纲 1.每秒仅上百请求的系统为何会OOM(RPC超时时间设置过长导致QPS翻几倍) 2.Jetty服务器的NIO机制如何导致堆外内存溢出(S区太小 禁NIO的显式GC) 3.一次微服务架构下的RPC调用引发的OOM故障排查实践(MAT案例) 4.一次没有WHERE条件的SQL语句引发的OOM问题排查实践(使用MA…...

client-go 的 QPS 和 Burst 限速

1. 什么是 QPS 和 Burst &#xff1f; 在 kubernetes client-go 中&#xff0c;QPS 和 Burst 是用于控制客户端与 Kubernetes API 交互速率的两个关键参数&#xff1a; QPS (Queries Per Second) 定义&#xff1a;表示每秒允许发送的请求数量&#xff0c;即限速器的平滑速率…...

使用docker-compose安装Redis的主从+哨兵模式

必看 本文是一主二从一哨兵模式&#xff1b;其余的单机/集群/多哨兵模式的话&#xff0c;不在本文... 本文的环境主要是&#xff1a;应用app在本地&#xff0c;redis在云服务器上&#xff1b; 图解 图如下&#xff1a;这个图很重要&#xff1b; 之所以要这样画图&#xff0…...

数据结构(Java版)第七期:LinkedList与链表(二)

专栏&#xff1a;数据结构(Java版) 个人主页&#xff1a;手握风云 一、链表的实现&#xff08;补&#xff09; 接上一期&#xff0c;下面我们要实现删除所有值为key的元素&#xff0c;这时候有的老铁就会想用我们上一期中讲到的remove方法&#xff0c;循环使用remove方法&#…...

ant-design-vue 1.X 通过id获取a-input组件失败

1.ant-design-vue 1.X 问题描述 当我在a-form组件中&#xff0c;以v-decorator指令绑定表单组件时&#xff0c;无法根据我设置的verify-code-input获取元素 <a-input type"text" id"verify-code-input" class"paIpt":placeholder"$t(…...

Flutter:吸顶效果

在分页中&#xff0c;实现tab吸顶。 TDNavBar的screenAdaptation: true, 开启屏幕适配。 该属性已自动对不同手机状态栏高度进行适配。我们只需关注如何实现吸顶。 view import package:ducafe_ui_core/ducafe_ui_core.dart; import package:flutter/material.dart; import p…...

MATLAB语言的数据类型

MATLAB语言的数据类型详解 MATLAB&#xff08;矩阵实验室&#xff09;是一种广泛应用于科学计算、数据分析、算法开发及模型构建的高性能语言和环境。MATLAB的强大之处不仅在于其丰富的数学工具和可视化功能&#xff0c;还有其灵活多变的数据类型。这篇文章将详细介绍MATLAB中…...

priority_queue优先队列

目录 1. 最短路径算法&#xff08;Dijkstra算法&#xff09; 应用场景&#xff1a; 优先队列的作用&#xff1a; 2. 最小生成树算法&#xff08;Prim算法&#xff09; 应用场景&#xff1a; 优先队列的作用&#xff1a; 3. 哈夫曼编码&#xff08;Huffman Coding&#x…...

HarmonyOS 鸿蒙Next 预览pdf文件

HarmonyOS 鸿蒙Next 预览pdf文件 1、使用filePreview 2、使用web组件 在线pdf&#xff08;网址是直接下载的&#xff0c;不是直接可以预览的&#xff09;&#xff0c;先下载再预览 import media from ohos.multimedia.media;import web_webview from ohos.web.webview;import …...

vscode开启调试模式,结合Delve调试器调试golang项目详细步骤

1.前期准备 (1).在vs code中的扩展程序中搜索并安装Go扩展程序 (2).安装 Delve 调试器 go install github.com/go-delve/delve/cmd/dlvlatest (3).打开vs code的命令面板&#xff0c;输入Go: Install/Update Tools&#xff0c;并单击该命令执行&#xff0c;安装或更新Go语…...

身份鉴权(PHP)(小迪网络安全笔记~

免责声明&#xff1a;本文章仅用于交流学习&#xff0c;因文章内容而产生的任何违法&未授权行为&#xff0c;与文章作者无关&#xff01;&#xff01;&#xff01; 附&#xff1a;完整笔记目录~ ps&#xff1a;本人小白&#xff0c;笔记均在个人理解基础上整理&#xff0c;…...

【git】-初始git

一、什么是版本控制&#xff1f; 二、Git的安装 三、掌握Linux常用命令 四、Git基本操作 1、提交代码 2、查看历史提交 3、版本回退 一、什么是版本控制&#xff1f; 版本控制是一种用于记录文件或项目内容变化的系统。它通过版本标识和版本历史记录来管理不同版本&#…...

CSS 盒模型

盒模型 CSS盒模型是网页布局的核心概念之一&#xff0c;它描述了网页元素的物理结构和元素内容与周围元素之间的关系。根据W3C规范&#xff0c;每个HTML元素都被视为一个矩形盒子&#xff0c;这个盒子由以下四个部分组成&#xff1a; 内容区&#xff08;Content area&#xff…...

[0405].第05节:搭建Redis主从架构

Redis学习大纲 一、3主3从的集群配置&#xff1a; 1.1.集群规划 1.分片集群需要的节点数量较多&#xff0c;这里我们搭建一个最小的分片集群&#xff0c;包含3个master节点&#xff0c;每个master包含一个slave节点&#xff0c;结构如下&#xff1a; 2.每组是一主一从&#x…...

6 分布式限流框架

限流的作用 在API对外互联网开放的情况下&#xff0c;是无法控制调用方的行为的。当遇到请求激增或者黑客攻击的情况下&#xff0c;会导致接口占用大量的服务器资源&#xff0c;使得接口响应效率的降低或者超时&#xff0c;更或者导致服务器宕机。 限流是指对应用服务进行限制…...

sosadmin相关命令

sosadmin命令 以下是本人翻译的官方文档&#xff0c;如有不对&#xff0c;还请指出&#xff0c;引用请标明出处。 原本有个对应表可以跳转的&#xff0c;但是CSDN的这个[](#)跳转好像不太一样&#xff0c;必须得用html标签&#xff0c;就懒得改了。 sosadmin help 用法 sosadm…...

关于大数据的基础知识(四)——大数据的意义与趋势

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于大数据的基础知识&#xff08;四&a…...

【EI,Scopus检索 | 往届均已检索见刊】第四届智能系统、通信与计算机网络国际学术会议(ISCCN 2025)

重要信息&#xff1a; 大会官网&#xff1a;更多详情【论文投稿】 截稿时间&#xff1a;以官网信息为准 大会时间&#xff1a;2025年2月21-23日 接受/拒稿通知&#xff1a;投稿后3-5个工作日内 收录检索&#xff1a;EI&#xff0c;Scopus 出版信息&#xff1a; 本会议所有…...

smplx blender插件笔记

目录 liunx安装&#xff1a; liunx安装&#xff1a; pip install smplx 这个创建模型报错 SMPL_blender_addon...

【算法】移除元素

今天讲的是力扣题目的题解&#xff1a; 力扣题目&#xff1a; 72.移除元素 题目描述&#xff1a; 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不…...

【后端面试总结】设计一个分布式锁需要考虑哪些东西

分布式锁是我们在分布式场景中经常用到的一种技术&#xff0c;在后端面试中也是出镜率很高&#xff0c;那么我们设计分布式锁的时候应该从那几方面去考虑呢 实现分布式锁需要考虑的点 设置超时时间 设置超时时间的目的是为了避免这个场景&#xff1a;进程A拿了锁&#xff0c…...

awr报告无法生成:常见案例与解决办法

awr报告无法生成:常见案例与解决办法 STATISTICS_LEVEL设置过低数据库打开状态不对主库隐含参数设置错误MMON子进程被SuspendSYS模式统计信息过期WRH$_SQL_PLAN表数据量太大AWR绑定变量信息收集超时撞上数据库Bug 9040676STATISTICS_LEVEL设置过低 STATISTICS_LEVEL设置为BAS…...

Hadoop 生态之 kerberos

参考链接 https://winway.github.io/2022/04/02/kerberos-ranger/ https://ieevee.com/tech/2016/06/22/ranger-2.html kerberos解决”who are you“的问题 ranger解决”what you can do“的问题 LDAP 轻型目录访问协议&#xff08;英文&#xff1a;Lightweight Director…...

【文件I/O】文件持久化

这篇文章详细讲解的是 理解在Linux操作系统中输入/输出&#xff08;I/O&#xff09;编程与文件操作的关系。 在计算机编程中&#xff0c;输入/输出编程&#xff08;I/O 编程&#xff09; 是一个重要的概念&#xff0c;指的是通过程序与外部世界&#xff08;如用户输入、文件、…...

USB学习——基本概念

文章目录 USB&#xff08;Universal Serial Bus&#xff09;概述USB系统的描述USB总线传输方式USB的拓扑结构 USB的连接模型USB控制器及分类USB描述符USB 端点USB枚举过程USB 四种传输类型USB 事务批量传输(Bulk)中断传输(Interrupt)等时传输(Isochronous)控制传输(Control)端点…...

南山网站优化/谷歌三件套下载

1、首先下载arm-linux-gcc-4.4.3.tgz到任意的目录下&#xff0c;然后解压。 2、将arm-linux-gcc 安装到/opt/Friendlyarm/4.4.3 目录。 3、在/usr/local/下建立 arm的文件夹&#xff0c;并修改属性 mkdir arm chmod 777 arm 4、把 opt下的4.4.3 目录复制到 /usr/local/arm下 su…...

冷库网站建设毕业论文/广州权威发布

实战需求 vlookup如何实现三变量查找,三个条件字段查询数据? 文章目录 《示例 1 – 查找 Brad 的数学分数》《示例 2 – 双向查找》《示例 3 – 使用下拉列表作为查找值》《示例 4 – 三向查找》什么是三向查找? 在示例 2 中,我们使用了一个查找表,其中包含不同科目学…...

WordPress建站维护服务/成都网站优化

文章目录 零、写在前面一、概念定义二、题目描述三、算法详解四、源码剖析五、推荐专栏六、习题练习零、写在前面 这是《算法零基础100讲》 专栏打卡学习的第 64 天了。如果觉得本专栏太贵无法承受,在博主主页添加博主好友,获取 付费专栏优惠券。   每天专栏的题,做不出来…...

世界500强企业排名中国企业/seo外包一共多少钱

养玉麒麟&#xff0c;用点“养根土”&#xff0c;一棵小苗变“威武老桩”&#xff0c;就这么简单玉麒麟大家应该都不陌生吧&#xff0c;他是大戟科的植物&#xff0c;他的整个植株是由变态茎所组成的&#xff0c;形态各异&#xff0c;非常的漂亮&#xff0c;比较适合当作盆景养…...

网络营销如何进行网站推广/关键词爱站网

1、对Tags进行管理 设置一个全局的类&#xff0c;类似如下&#xff1a; public class Tags:MonoBehaviour{public const string player"Player"; } 调用Tags.player 2、发送消息 unity中每一个对象都有SendMessage&#xff0c;BroadcastMessage&#xff0c;SendMessa…...

成全视频免费观看在线看电视剧/网站优化推广哪家好

最近偶有开发同事咨询 PostgreSQL 日期函数&#xff0c;对日期处理不太熟悉&#xff0c;今天详细看了下手册的日期函数&#xff0c;整理如下&#xff0c;供参考。 一 取当前日期的函数 --取当前时间skytf> select now(); now ---------------…...