当前位置: 首页 > 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、深层理解【程序…...

前端高级质感按钮复用指南

前端高级质感按钮复用指南为解决项目中按钮样式混乱、交互手感不一致的问题&#xff0c;我们沉淀了这套克制型高级质感按钮可复用方案。 它兼顾了高级视觉层次与真实物理交互手感&#xff0c;无需复杂定制即可快速在项目中落地&#xff0c;尤其适合顶部 Tab、筛选切换、状态标签…...

Arduino_AVRSTL:面向AVR单片机的轻量C++ STL子集

1. Arduino_AVRSTL 库深度解析&#xff1a;面向资源受限 AVR 平台的 C 标准库子集移植1.1 项目定位与工程价值Arduino_AVRSTL 是对原始 ArduinoSTL 库的一次关键性平台适配&#xff0c;其核心目标并非完整复刻 ISO/IEC 14882 标准定义的 STL&#xff08;Standard Template Libr…...

EMDB:面向MCU的嵌入式键值数据库设计与实践

1. 项目概述EMDB&#xff08;Embedded Micro Database&#xff09;是一个专为资源受限嵌入式系统设计的极简型键值数据库&#xff0c;其核心目标是在微控制器级别提供可查询、可持久化、内存友好的数据管理能力。与传统嵌入式KV存储&#xff08;如简单的哈希表或链表缓存&#…...

【故障公告】数据库服务器磁盘 MBPS 高造成 :-: 期间全站故障

简介 langchain中提供的chain链组件&#xff0c;能够帮助我门快速的实现各个组件的流水线式的调用&#xff0c;和模型的问答 Chain链的组成 根据查阅的资料&#xff0c;langchain的chain链结构如下&#xff1a; $$Input \rightarrow Prompt \rightarrow Model \rightarrow Outp…...

《信号完整性》专栏简介

大家好&#xff0c;我是一只豌豆象&#xff0c;一名长期从事信号完整性设计分析的电子工程师&#xff0c;凭着对技术知识的无尽渴望和对技术工作的不断追求&#xff0c;再辅以极高的学习热情&#xff0c;使得我能够十年如一日的高效深耕于电子产品的设计研发领域。 在已过去的…...

客户和采购都在用豆包、deepseek查资料,怎么才能让这些国内头部大模型在回答时优先推荐公司的产品?

随着人工智能技术的爆发&#xff0c;企业获客与消费者决策的路径正在发生深刻的重构。据近期的公开市场调研与行业报告显示&#xff0c;包括豆包、DeepSeek、文心一言在内的国内头部大模型&#xff0c;其月活跃用户数正呈现指数级增长。一个不可忽视的趋势是&#xff1a;无论是…...

DAY3--SQL单字段去重查询

SQL基础入门&#xff1a;电商用户数据单字段去重查询实操 这一章能解决什么电商工作问题&#xff1f; 前两章我们学了SELECT *&#xff08;全量看数据&#xff09;和SELECT 字段列表&#xff08;精准取字段&#xff09;。这一章讲的是另一个高频操作&#xff1a;去重。 我讲一个…...

单片机驱动MOS管的原理与实战技巧

1. 单片机直接驱动MOS管的原理与风险MOS管作为现代电子设计中最常用的功率开关器件&#xff0c;其控制方式看似简单却暗藏玄机。作为一名经历过多次"炸管"教训的硬件工程师&#xff0c;我想分享一些关于单片机直接驱动MOS管的实战经验。MOS管分为NMOS和PMOS两种类型&…...

《深入理解Mybatis原理》MyBatis动态SQL原理

在技术领域&#xff0c;我们常常被那些闪耀的、可见的成果所吸引。今天&#xff0c;这个焦点无疑是大语言模型技术。它们的流畅对话、惊人的创造力&#xff0c;让我们得以一窥未来的轮廓。然而&#xff0c;作为在企业一线构建、部署和维护复杂系统的实践者&#xff0c;我们深知…...

国内大模型托管平台推荐:四大平台选型指南

随着大模型技术加速落地&#xff0c;模型托管平台已成为开发者不可或缺的基础设施。本文梳理了2025年国内主流的四大大模型托管平台&#xff0c;从核心优势、适用场景到选型建议&#xff0c;为你提供一份实用的选型指南。一、模力方舟&#xff1a;国产开源生态的“基石”推荐指…...