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

C++ 并发编程指南(11)原子操作 | 11.4、通过内存序实现顺序模型

文章目录

  • 一、通过内存序实现顺序模型
    • 1、Relaxed Ordering
    • 2、Sequencial Consistent Ordering
    • 3、Acquire Release Ordering

前言

前文介绍了六种内存顺序,以及三种内存模型,本文通过代码示例讲解六种内存顺序使用方法,并实现相应的内存模型。

一、通过内存序实现顺序模型

1、Relaxed Ordering

memory_order_relaxed 表示“最宽松的内存序”,不提供任何同步保证。具体来说,memory_order_relaxed 仅保证原子操作本身是原子的,但不保证操作之间的顺序。

memory_order_relaxed 的语义下,编译器和处理器可能会对原子操作进行重排序,以提高性能。在多线程环境中,使用 memory_order_relaxed 的原子操作可能会产生不可预测的结果,因为线程之间的操作顺序可能会因为重排序而发生变化。例如:

std::atomic<bool> x, y;
std::atomic<int> z;void write_x_then_y() {x.store(true, std::memory_order_relaxed);  // 1y.store(true, std::memory_order_relaxed);  // 2
}void read_y_then_x() {while (!y.load(std::memory_order_relaxed)) { // 3std::cout << "y load false" << std::endl;}if (x.load(std::memory_order_relaxed)) { //4++z;}
}void TestOrderRelaxed() {std::thread t1(write_x_then_y);std::thread t2(read_y_then_x);t1.join();t2.join();assert(z.load() != 0); // 5
}

在上面的程序中断言有可能被触发,线程A执行write_x_then_y函数,线程B执行read_y_then_x函数。由于使用宽松内存序,操作1对应的指令可能重排到操作2对应的指令后面,此时,当线程A执行完操作2时,操作1还没有被执行,x对应的值还没有写入到内存(x=false、y=true)。线程2执行到操作3时,读到y为true退出循环,线程2看到的x的值为false时(可以从指令重排缓存结构两个角度来理解),不会执行操作4,进而导致断言触发。

注意:虽然 memory_order_relaxed 不提供同步保证,但它仍然可以用于某些不需要严格同步的场景。例如,在某些计数器或统计场景中,可以使用宽松内存序来提高性能,因为这些场景通常不需要严格的同步语义。

2、Sequencial Consistent Ordering

memory_order_seq_cst 代表了顺序一致性(Sequentially Consistent)的内存模型。这种内存序提供了最严格的同步保证,它确保所有线程都将看到相同的操作顺序,并且所有原子操作都将按照程序顺序执行。

具体来说,当使用 memory_order_seq_cst 进行原子操作时,编译器和处理器不会对这些操作进行任何形式的重排序,以确保在所有线程中看到的操作顺序是一致的。这种内存序适用于那些需要强一致性的场景,但也可能带来一定的性能开销。

使用memory_order_seq_cst内存序,解决前面遇到的问题,如下:


void write_x_then_y() {x.store(true, std::memory_order_seq_cst);  // 1y.store(true, std::memory_order_seq_cst);  // 2
}void read_y_then_x() {while (!y.load(std::memory_order_seq_cst)) { // 3std::cout << "y load false" << std::endl;}if (x.load(std::memory_order_seq_cst)) { //4++z;}
}void TestOrderSeqCst() {std::thread t1(write_x_then_y);std::thread t2(read_y_then_x);t1.join();t2.join();assert(z.load() != 0); // 5
}

上面的代码x和y采用的是memory_order_seq_cst,当线程2执行到操作3,读出来y的值为true时会退出循环。因为使用的是全局一致性模型,不会对指令顺序进行优化,操作1一定会在操作2前面执行,所以当y的值被修改成成true时(执行操作2),操作1一定被执行了,此时,在线程2看到的x的值为true,会执行操作4,进而断言不会被触发。

注意:实现 sequencial consistent 模型有一定的开销,现代 CPU 通常有多核,每个核心还有自己的缓存,为了做到全局顺序一致,每次写入操作都必须同步给其他核心。为了减少性能开销,如果不需要全局顺序一致,应该考虑使用更加宽松的顺序模型。

3、Acquire Release Ordering

Acquire Release Ordering 模型中,会使用 memory_order_acquirememory_order_releasememory_order_acq_rel 这三种内存顺序,具体用法如下:

  • memory_order_acquire:原子变量的 load 操作可以使用,称为 acquire 操作
  • memory_order_release:原子变量的 store 操作可以使用,称为 release 操作
  • memory_order_acq_rel:read-modify-write 操作即读 (load) 又写 (store),可以使用 memory_order_acquirememory_order_releasememory_order_acq_rel。如果使用 memory_order_acquire则作为 acquire 操作;如果使用 memory_order_release,则作为 release 操作;如果使用 memory_order_acq_rel,则同时为两者

Acquire-release 可以实现 synchronizes-with 关系(该关系的解释可以参考11.5章节),可以通过Acquire-release 修正 TestOrderRelaxed函数以达到同步的效果,如下:

void TestReleaseAcquire() {std::atomic<bool> rx, ry;std::thread t1([&]() {rx.store(true, std::memory_order_relaxed); // 1ry.store(true, std::memory_order_release); // 2});std::thread t2([&]() {while (!ry.load(std::memory_order_acquire)); //3assert(rx.load(std::memory_order_relaxed)); //4});t1.join();t2.join();
}

采用Acquire-release 模型,操作3与操作2构成 synchronizes-with 关系,操作2的结果对操作3可见。当操作3读取到y的值为true时,说明操作2一定被执行了,操作2使用的是memory_order_release内存序,操作1指令不会被优化到操作2后面(参考11.3对memory_order_release内存序的介绍),操作2执行了,那么操作1也一定会被执行,线程2此时读到y=true、x=true,操作4一定会被执行,断言不会被触发。

相关文章:

C++ 并发编程指南(11)原子操作 | 11.4、通过内存序实现顺序模型

文章目录 一、通过内存序实现顺序模型1、Relaxed Ordering2、Sequencial Consistent Ordering3、Acquire Release Ordering 前言 前文介绍了六种内存顺序&#xff0c;以及三种内存模型&#xff0c;本文通过代码示例讲解六种内存顺序使用方法&#xff0c;并实现相应的内存模型。…...

【数据结构】栈和队列专题

前言 上篇博客我们讨论了栈和队列的有关结构&#xff0c;本篇博客我们继续来讨论有关栈和队列习题 这些题算是经典了 &#x1f493; 个人主页&#xff1a;小张同学zkf ⏩ 文章专栏&#xff1a;数据结构 若有问题 评论区见&#x1f4dd; &#x1f389;欢迎大家点赞&#x1f44d…...

2024年程序员最应该关注的几件事?

对于程序员而言&#xff0c;技术和行业趋势的演变是持续关注的焦点。以下是几件2024年程序员应该关注的事情&#xff1a; 持续学习新技术&#xff1a;技术领域的快速变化要求程序员不断更新自己的技能集&#xff0c;包括编程语言、框架、工具和最佳实践。 人工智能与机器学习&…...

【初阶数据结构】单链表基础OJ题讲解

前言 &#x1f4da;作者简介&#xff1a;爱编程的小马&#xff0c;正在学习C/C&#xff0c;Linux及MySQL。 &#x1f4da;本文收录与初阶数据结构系列&#xff0c;本专栏主要是针对时间、空间复杂度&#xff0c;顺序表和链表、栈和队列、二叉树以及各类排序算法&#xff0c;持…...

基于Java的俄罗斯方块游戏的设计与实现

关于俄罗斯方块项目源码.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89300281 基于Java的俄罗斯方块游戏的设计与实现 摘 要 俄罗斯方块是一款风靡全球&#xff0c;从一开始到现在都一直经久不衰的电脑、手机、掌上游戏机产品&#xff0c;是一款游戏规则简单…...

Hadoop 3.4.0+HBase2.5.8+ZooKeeper3.8.4+Hive+Sqoop 分布式高可用集群部署安装 大数据系列二

创建服务器,参考 虚拟机创建服务器 节点名字节点IP系统版本master11192.168.50.11centos 8.5slave12192.168.50.12centos 8.5slave13192.168.50.13centos 8.5 1 下载组件 Hadoop:官网地址 Hbase:官网地址 ZooKeeper:官网下载 Hive:官网下载 Sqoop:官网下载 为方便同学…...

umi搭建react项目

UMI 是一个基于 React 的可扩展企业级前端应用框架&#xff0c;提供路由、状态管理、构建和部署等功能&#xff0c;可以帮助开发者快速构建复杂的单页面应用&#xff08;SPA&#xff09;和多页面应用&#xff08;MPA&#xff09;。它与 React 的关系是&#xff0c;UMI 构建在 R…...

mybatis-plus之数据源切换事务失效问题

为什么存在数据源切换和食物时效问题&#xff1f; 由于业务数据来源不同 需要配置多个数据源来进行数据的查询 编辑等操作 这一切换业务对数据的一致性要求很高那就要保证ACID啦 也就是数据的有效性 要么是成功的 要么是失败的。 数据源切换采用mybatisplus支持 多数据源配置&a…...

vue 百度地图点击marker修改marker图片,其他marker图片不变。

解决思路&#xff0c;就是直接替换对应marker的图片。获取marker对象判断点击的marker替换成新图片&#xff0c;上一个被点击的就替换成老图片。 marker.name tag;marker.id i; //一定要设置id&#xff0c;我这里是设置的循环key值&#xff0c;要唯一性。map.addOverlay(mark…...

【Javaer学习Python】 1、Django安装

安装 Python 和 PyCharm 的方法就略过了&#xff0c;附一个有效激活PyCharm的链接&#xff1a;https://www.quanxiaoha.com/pycharm-pojie/pycharm-pojie-20241.html 1、安装Django # 安装Django pip install Django# 查看当前版本 python -m django --version 5.0.62、创建项…...

SSL协议

SSL 安全传输协议&#xff08;安全套接层&#xff09; 也叫TLS ---- 传输层安全协议 SSL的工作原理&#xff1a;SSL协议因为是基于TCP协议工作的&#xff0c;通信双方需要先建立TCP会话。因为SSL协议需要进行安全保证&#xff0c;需要协商安全参数&#xff0c;所以也需要建立…...

什么情况下会造成索引失效?

2.3.4. 索引失效 对索引使用左或者左右模糊匹配 使用左或者左右模糊匹配的时候&#xff0c;也就是 like %xx 或者 like %xx% 这两种方式都会造成索引失效。但是如果前缀是确定的那么就可以使用到索引&#xff0c;例如 name like 许%。 因为索引 B 树是按照「索引值」有序排列…...

间隔采样视频的代码

项目统计模型准确率 项目会保存大量视频&#xff0c;为了统计模型的精度&#xff0c;我们想要十五分钟抽取一个视频用来统计。 import os import shutil from datetime import datetime, timedelta #抽取视频的代码&#xff0c;会在每个小时的0分、15分、30分、45分取一个命名…...

C++ QT设计模式 (第二版)

第3章 Qt简介 3.2 Qt核心模块 Qt是一个大库&#xff0c;由数个较小的库或者模块组成&#xff0c;最为常见的如下&#xff1a;core、gui、xml、sql、phonon、webkit&#xff0c;除了core和gui&#xff0c;这些模块都需要在qmake的工程文件中启用 QTextStream 流&#xff0c;Qdat…...

【经验总结】超算互联网服务器 transformers 加载本地模型

1. 背景 使用 超算互联网 的云服务&#xff0c;不能连接外网&#xff0c;只能把模型下载到本地&#xff0c;再上传上去到云服务。 2. 模型下载 在 模型中 https://huggingface.co/models 找到所需的模型后 点击下载 config.json pytorch_model.bin vocab.txt 3. 上传模型文…...

ubuntu编译pcl时报错

报错如下 cc1plus: warning: -Wabi wont warn about anything [-Wabi] cc1plus: note: -Wabi warns about differences from the most up-to-date ABI, which is also used by default cc1plus: note: use e.g. -Wabi11 to warn about changes from GCC 7 在网上找到了一封邮件…...

Rust中的单元测试

概述 Rust内置了单元测试的支持&#xff0c;这点和Golang一样&#xff0c;非常的棒&#xff0c;我超级喜欢单元测试&#xff01;&#xff01;&#xff01; 本节课的代码还是基于之前的求公约数的案例。 之前的完整代码如下&#xff1a; fn gcd(mut n: u64, mut m: u64) ->…...

ubuntu18.04系统安装pangolin

1. 安装pangolin依赖项 ctrlaltt 打开终端&#xff0c;依次输入下面的命令 sudo apt update sudo apt upgrade sudo apt install libglew-dev cmake libboost-dev libboost-thread-dev libboost-filesystem-dev libeigen3-dev -y 2.在终端中输入下面的命令&#xff0c;克隆…...

洛谷P10397题解

题目描述 给定一条 std::freopen 语句&#xff0c;输出其操作的文件名称。 形式化地&#xff0c;std::freopen 语句都应该恰好是 std::freopen("<title>","<mode>",<stream>);其中 <title> 为其操作的文件名称。其至少包含一个…...

【Linux】自动化编译工具——make/makefile(超细图例详解!!)

目录 一、前言 二、make / Makefile背景介绍 &#x1f95d;Makefile是干什么的&#xff1f; &#x1f347;make又是什么&#xff1f; 三、demo实现【见见猪跑&#x1f416;】 四、依赖关系与依赖方法 1、概念理清 2、感性理解【父与子&#x1f468;】 3、深层理解【程序…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...