[知识点] 内存顺序属性的用途和行为
C++标准库中定义了以下几种内存顺序属性:
std::memory_order_relaxed
std::memory_order_consume
std::memory_order_acquire
std::memory_order_release
std::memory_order_acq_rel
std::memory_order_seq_cst
1. std::memory_order_relaxed
- 定义:不提供同步或顺序保证,只保证原子操作本身的原子性。
- 用途:适用于不需要同步的情况下,用于计数器等场景。
- 行为:操作之间可以自由重排序,其他线程可能看到不同的操作顺序。
#include <atomic>
#include <iostream>
#include <thread>// 计数器,用于多线程递增
std::atomic<int> counter(0);void increment() {for (int i = 0; i < 1000; ++i) {// 使用 memory_order_relaxed 进行原子加操作// 不保证任何顺序,只保证原子性counter.fetch_add(1, std::memory_order_relaxed);}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();// 输出最终的计数器值std::cout << "Counter: " << counter.load(std::memory_order_relaxed) << std::endl;return 0;
}
2. std::memory_order_consume
- 定义:专用于指针依赖的消费操作,确保后续依赖操作的顺序。
- 用途:用于消费操作,确保依赖指针的操作不会被重排序到消费操作之前。
- 行为:类似于
memory_order_acquire
,但仅保证指针依赖的顺序。
#include <atomic>
#include <iostream>
#include <thread>// 原子指针,指向整数数据
std::atomic<int*> p;
int data;void producer() {data = 42;// 使用 memory_order_release 存储指针// 确保 data 的写入在存储指针之前完成p.store(&data, std::memory_order_release);
}void consumer() {int* ptr;// 使用 memory_order_consume 加载指针// 确保指针依赖的操作不会被重排序while (!(ptr = p.load(std::memory_order_consume)));// 输出指针指向的数据std::cout << "Data: " << *ptr << std::endl;
}int main() {std::thread t1(producer);std::thread t2(consumer);t1.join();t2.join();return 0;
}
3. std::memory_order_acquire
- 定义:获取操作,确保后续读写操作不会被重排序到获取操作之前。
- 用途:用于加载操作,以确保加载后的操作看到的是最新的数据。
- 行为:获取操作之前的读写操作可能被重排序,但之后的操作不会。
#include <atomic>
#include <iostream>
#include <thread>// 标志变量,用于同步
std::atomic<int> flag(0);
int data = 0;void writer() {data = 42;// 使用 memory_order_release 存储标志// 确保 data 的写入在存储标志之前完成flag.store(1, std::memory_order_release);
}void reader() {// 使用 memory_order_acquire 加载标志// 确保标志被加载后,读取 data 的操作不会被重排序while (flag.load(std::memory_order_acquire) != 1);// 输出 data 的值std::cout << "Data: " << data << std::endl;
}int main() {std::thread t1(writer);std::thread t2(reader);t1.join();t2.join();return 0;
}
4. std::memory_order_release
- 定义:释放操作,确保之前的读写操作不会被重排序到释放操作之后。
- 用途:用于存储操作,以确保存储前的所有操作完成。
- 行为:释放操作之后的读写操作可能被重排序,但之前的操作不会。
#include <atomic>
#include <iostream>
#include <thread>// 标志变量,用于同步
std::atomic<int> flag(0);
int data = 0;void writer() {data = 42;// 使用 memory_order_release 存储标志// 确保 data 的写入在存储标志之前完成flag.store(1, std::memory_order_release);
}void reader() {// 使用 memory_order_acquire 加载标志// 确保标志被加载后,读取 data 的操作不会被重排序while (flag.load(std::memory_order_acquire) != 1);// 输出 data 的值std::cout << "Data: " << data << std::endl;
}int main() {std::thread t1(writer);std::thread t2(reader);t1.join();t2.join();return 0;
}
5. std::memory_order_acq_rel
- 定义:获取和释放操作的组合,适用于读-修改-写操作。
- 用途:用于原子操作,如
compare_exchange
,以确保操作的前后都不会被重排序。 - 行为:操作之前和之后的读写操作都不会被重排序。
#include <atomic>
#include <iostream>
#include <thread>// 原子计数器,用于多线程递增
std::atomic<int> counter(0);void increment() {for (int i = 0; i < 1000; ++i) {int expected = counter.load(std::memory_order_relaxed);// 使用 memory_order_acq_rel 进行比较并交换操作// 确保操作之前和之后的读写顺序while (!counter.compare_exchange_weak(expected, expected + 1, std::memory_order_acq_rel));}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();// 输出最终的计数器值std::cout << "Counter: " << counter.load(std::memory_order_relaxed) << std::endl;return 0;
}
6. std::memory_order_seq_cst
- 定义:获取和释放操作的组合,适用于读-修改-写操作。
- 用途:用于原子操作,如
compare_exchange
,以确保操作的前后都不会被重排序。 - 行为:操作之前和之后的读写操作都不会被重排序。
#include <atomic>
#include <iostream>
#include <thread>// 原子变量
std::atomic<int> x(0), y(0);
int r1, r2;void thread1() {// 使用 memory_order_seq_cst 存储 x// 确保全局顺序一致x.store(1, std::memory_order_seq_cst);// 使用 memory_order_seq_cst 加载 y// 确保全局顺序一致r1 = y.load(std::memory_order_seq_cst);
}void thread2() {// 使用 memory_order_seq_cst 存储 y// 确保全局顺序一致y.store(1, std::memory_order_seq_cst);// 使用 memory_order_seq_cst 加载 x// 确保全局顺序一致r2 = x.load(std::memory_order_seq_cst);
}int main() {std::thread t1(thread1);std::thread t2(thread2);t1.join();t2.join();// 输出结果std::cout << "r1: " << r1 << ", r2: " << r2 << std::endl;return 0;
}
总结
std::memory_order_relaxed
: 最弱的同步和顺序保证,仅保证原子操作本身的原子性。std::memory_order_consume
: 专用于指针依赖,确保后续依赖操作的顺序。std::memory_order_acquire
: 获取操作,确保后续读写操作不会被重排序到获取操作之前。std::memory_order_release
: 释放操作,确保之前的读写操作不会被重排序到释放操作之后。std::memory_order_acq_rel
: 获取和释放操作的组合,适用于读-修改-写操作。std::memory_order_seq_cst
: 顺序一致性操作,提供最强的同步和顺序保证。
相关文章:
[知识点] 内存顺序属性的用途和行为
C标准库中定义了以下几种内存顺序属性: std::memory_order_relaxedstd::memory_order_consumestd::memory_order_acquirestd::memory_order_releasestd::memory_order_acq_relstd::memory_order_seq_cst 1. std::memory_order_relaxed 定义:不提供同步…...
JAVA Mongodb 深入学习(二)索引的创建和优化
一、常用索引类型 1、单个索引 单个索引的创建 db.你的表名.createIndex({"你的字段名":1}) 单个索引的创建且是唯一索引 db.你的表名.createIndex({"你的字段名":1}),{ unique: true }) 2、复合索引 将多个过滤的字段,做成索引,…...

转让北京劳务分包地基基础施工资质条件和流程
地基基础资质转让流程是怎样的?对于企业来说,资质证书不仅是实力的证明,更是获得工程承包的前提。而在有了资质证书后,企业才可以安心的准备工程投标,进而在工程竣工后获得收益。而对于从事地基基础工程施工的企业,需…...

Python基础——字符串
一、Python的字符串简介 Python中的字符串是一种计算机程序中常用的数据类型【可将字符串看作是一个由字母、数字、符号组成的序列容器】,字符串可以用来表示文本数据。 通常使用一对英文的单引号()或者双引号(")…...
AP的数据库性能到底重要吗?
先说结论:没那么重要。甚至可能不重要。 我用我的经历和分析给大家说说。诸位看看如何。 不重要的观点是不是不能接受? 因为这些是站在我们角度觉得的。而实际上使用者(业务或者用户),真的不太在乎我们所在乎的。 …...

Vue3【二】 VSCode需要安装的Vue语法插件
VSCode需要安装的 适配Vue3的插件 Vue-Official插件安装...

设置路径别名
一、描述 如果想要给路径设置为别名,就是常见的有些项目前面的引入文件通过开头的,也就是替换了一些固定的文件路径,怎么配置。 二、配置 import { defineConfig } from vite import react from vitejs/plugin-react import path from path…...

人事信息管理系统(Java+MySQL)
一、项目背景 在现代企业中,管理大量员工的工作信息、薪资、请假、离职等事务是一项非常繁琐和复杂的任务。传统的手工管理方式不仅效率低下,而且容易出错。为了提高人事管理的效率,减少人工操作带来的错误,企业迫切需要一个高效…...
Python 中生成器与普通函数的区别
在Python中,生成器和普通函数有一些区别。 生成器使用 yield 语句从函数中返回一个值,而不是使用 return 语句。当生成器函数被调用时,它会返回一个迭代器对象,而非立即执行函数体内的代码。 生成器函数可以通过多次调用 yield 语…...

最小栈、栈的弹出(C++)
1.最小栈 思路分析: 代码: class MinStack { public:MinStack() {}void push(int val) {st.push(val);//两种情况需要更新最小值//1.最小栈为空(就是存最小值的那个栈)//2.插入的值小于或等于最小栈的栈顶元素if(minstack.empty()||minstack.top()>…...

20240607每日通信--------VUE3前端引入scoket-io,后端引入Netty-SocketIO,我成功了,希望一起交流沟通
无语 前置: VUE3 前端集成scoket-io socket.io-client Sringboot 3.0JDK17集成Netty-SocketIO Netty-SocketIO 失败原因一: 前期决定要写demo时候,单独了解了,后端引入Netty-SocketIO注意事项,详见我先头写的博客 前…...

Tomcat源码解析(八):一个请求的执行流程(附Tomcat整体总结)
Tomcat源码系列文章 Tomcat源码解析(一):Tomcat整体架构 Tomcat源码解析(二):Bootstrap和Catalina Tomcat源码解析(三):LifeCycle生命周期管理 Tomcat源码解析(四):StandardServer和StandardService Tomcat源码解析(五)&…...
python使用gdb进行堆栈查看与调试
以ubuntu示例,先安装gdb与python-dbg,dbg按照python版本安装 apt install -y gdb python3.10-dbg 使用top查看python进程,使用gdb操作python进程 gdb python3 6618 加载环境 source /usr/share/gdb/auto-load/usr/bin/python3.10-gdb.py…...
【DevOps】路由与路由器详细介绍:原理、功能、类型及应用场景
目录 一、路由详细介绍 1、什么是路由? 2、路由的基本原理 3、 路由协议 静态路由 动态路由 4、 路由表 5、 路由算法 6、路由的优缺点 优点 缺点 7、 路由应用场景 二、路由器详细介绍 1、什么是路由器? 2、 路由器的工作原理 3、路由器…...

【WP|9】深入解析WordPress [add_shortcode]函数
add_shortcode 是 WordPress 中一个非常强大的函数,用于创建自定义的短代码(shortcodes)。短代码是一种简洁的方式,允许用户在内容中插入动态的、可重用的功能。通过 add_shortcode,开发者可以定义自己的短代码&#x…...
Qt QStackedWidget类详细分析
一.定义 QStackedWidget类是一个容器控件,它提供了一个堆叠的页面布局方式,每个页面可以包含一个子部件。在QStackedWidget中,只有当前活动的页面是可见的,其他页面会被隐藏起来。 QStackedWidget类的常用方法包括: a…...
Java数据结构与算法(leetcode热题881. 救生艇)
前言 救生艇属于贪心算法,解题之前条件一定要归纳好。题目中存在3个要求: 1.一艘船最多坐2人 2.船数要求最小 3.每艘船重量小于limit 意味着体重较轻的两人可以同乘一艘救生艇。 . - 力扣(LeetCode) 实现原理 1.重量大的有…...
react+wijmo所遇问题
1.官网地址:https://demo.mescius/wijmo/demos/Grid/Overview/react 别进中文地址,注意后缀mescius有没有.cn有的话删掉,那个没有触发方法和各类API,组件也不全 2.中文地址:(不太好用)&#x…...

手撕设计模式——克隆对象之原型模式
1.业务需求 大家好,我是菠菜啊,前俩天有点忙,今天继续更新了。今天给大家介绍克隆对象——原型模式。老规矩,在介绍这期之前,我们先来看看这样的需求:《西游记》中每次孙悟空拔出一撮猴毛吹一下&#x…...

LangChain基础知识入门
LangChain的介绍和入门 1 什么是LangChain LangChain由 Harrison Chase 创建于2022年10月,它是围绕LLMs(大语言模型)建立的一个框架,LLMs使用机器学习算法和海量数据来分析和理解自然语言,GPT3.5、GPT4是LLMs最先进的代…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...