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

理解原子变量之二:从volatile到内存序-进一步的认识

目录

实例1

实例2

实例3

内存序中两个最重要的概念

补记

结论


实例1

看下面的例子:在vs2013中建立如下工程:

#include <thread>
#include <iostream>
#include <chrono>bool done = false;void worker(){std::this_thread::sleep_for(std::chrono::seconds(3));done = true;
}int main(){std::thread workerThread(worker);while (!done){//std::cout << "waiting" << std::endl;不知为什么,加上这句打印就可以跳出循环}std::cout << "thread finished" << std::endl;workerThread.join();std::cin.get();return 0;
}

使用release模式编译该工程,且优化采用O2

结果是程序卡住了,本来3秒钟就可以跳出while(!done)死循环,现在一直停着。

vs2013 release 模式下多线程卡住演示

实例2

实例1为什么会卡住呢?因为编译器在打开优化的情况下,“武断”的认为done永远都是false。编译器意识不到子线程也在改变done的取值,所以就认为done是常量,而不会在运行到while()时读取done的实际值,于是while(!done)就变成了while(true)。假如采用debug模式编译,编译器不会“自作聪明”,程序在运行时将老老实实的不断读取done的实时值,直到done==true为止。所以,debug模式不会卡住,而release模式会卡住(除非在编译时禁止优化)。

现在稍微修改一下代码,用volatile修饰 bool done。即使在release下编译,程序仍然正常走完,不卡住:

这是因为,volatile在提示编译器,done是一个不能被优化掉的变量。即使在release模式下,每次走到while时,也要查看done的值。

回到原子变量的话题上来,再看第三个例子:

实例3

现在用atomic<bool>代替volatile bool。

#include <thread>
#include <iostream>
#include <chrono>
#include <atomic>std::atomic<bool> done(false);void worker() {std::this_thread::sleep_for(std::chrono::seconds(3));done.store(true);
}int main() {std::thread workerThread(worker);while (!done.load()) {//std::cout << "waiting" << std::endl;不知为什么,加上这句打印就可以跳出循环}std::cout << "thread finished" << std::endl;workerThread.join();std::cin.get();return 0;
}

结果与使用volatile一样,while(!done.load())不会一直阻塞程序向下运行:

 看到了上面的三个例子,接下来就要请出原子变量里面一个非常重要的概念:内存序。

内存序中两个最重要的概念

std::memory_order - cppreference.com列出了C++11标准里的六个内存序(memory_order)。这6个内存序的作用将在下一篇文章描述。其中多次出现一个词汇“可见”(visible)

以MEMORY_ORDER_ACQUIRE为例,其中文解释是:

有此内存定序的加载操作,在其影响的内存位置进行获得操作:当前线程中读或写不能被重排到此加载之前。其他线程的所有释放同一原子变量的写入,能为当前线程所见

 “其他线程的所有释放同一原子变量的写入,能为当前线程所见”这句话的意思是什么?我们只要理解了什么是不可见,就理解了可见。对照实例1,在不使用volatile的情况下,子线程workerThread对done的修改,没有影响到主线程的while(!done)逻辑,这就是说,子线程对done的写入,不为主线程可见。

反观实例2和3,子线程修改了done,主线程的运行随之受了影响,这就是可见。

内存序里有两个重要的概念,一是指令排序,在下一篇里面将介绍;另一个就是可见性(visibility)。从例子2和3可见,在可见性这方面,原子变量的作用与volatile是一样的:原子变量被一个线程改变后,另一个线程肯定会发现这个变化

补记

实例1,2,3都是在vs2013下演示的。在vs2019下,实例1效果有区别:vs2019的while循环在示例1中同样不会阻塞。这是因为,不同的编译器遵循不同的c++标准。即使遵循相同的C++标准,不同的编译器对同一个标准的贯彻程度也不一样:有的编译器严格遵循标准,既不多做,也不少做;有的编译器在某些次要方面可能达不到C++标准的要求(少做);还有的编译器为了安全性等方面考虑,甚至超过了C++标准的要求(多做)。vs2019很可能属于超过标准这一种:即使是多线程编程中使用普通的非原子变量,非易失(volatile)变量,仍能保证可见性(个人猜测)。

但无论如何,本文探讨的是C++11标准的内存序,不针对具体编译器。在遵守C++11标准方面,VS2013似乎比2019更贴切,所以三个实例均采用2013示范。

结论

前文解释了原子变量的第一个功能:它相当于粒度很细的互斥锁。本文介绍了原子变量的第二个功能:可见性。原子变量保证了多线程编程中的可见性。事实上,原子变量共负担了三个功能。下一篇文章将介绍其第三个功能--限制指令重排。

相关文章:

理解原子变量之二:从volatile到内存序-进一步的认识

目录 实例1 实例2 实例3 内存序中两个最重要的概念 补记 结论 实例1 看下面的例子&#xff1a;在vs2013中建立如下工程&#xff1a; #include <thread> #include <iostream> #include <chrono>bool done false;void worker(){std::this_thread::sle…...

DICOM标准:MR图像模块属性详解——磁共振成像(MR)在DICOM中的应用

目录 引言 磁共振成像&#xff08;MR&#xff09; 一、MR图像模块 二、MR图像属性描述 1、图像类型 (Image Type) 2、抽样每个象素 (Sampling per Pixel) 3、光度插值 (Photometric Interpretation) 4、位分配 (Bits Allocated) 结论 引言 数字成像和通信在医学&#xff08…...

Linux内核与用户空间

Linux内核与用户空间是Linux操作系统中的两个重要概念&#xff0c;它们各自承担着不同的功能和职责&#xff0c;并通过特定的机制进行交互。以下是对Linux内核与用户空间的详细解释&#xff1a; 一、Linux内核 定义&#xff1a;Linux内核是Linux操作系统的核心组件&#xff0c…...

计算机网络-以太网小结

前导码与帧开始分界符有什么区别? 前导码--解决帧同步/时钟同步问题 帧开始分界符-解决帧对界问题 集线器 集线器通过双绞线连接终端, 学校机房的里面就有集线器 这种方式仍然属于共享式以太网, 传播方式依然是广播 网桥: 工作特点: 1.如果转发表中存在数据接收方的端口信息…...

找树根和孩子c++

题目描述 给定一棵树&#xff0c;输出树的根root&#xff0c;孩子最多的结点max以及他的孩子 输入 第一行&#xff1a;n&#xff08;0<结点数<100&#xff09;&#xff0c;m&#xff08;0<边数<200&#xff09;。 以下m行&#xff1b;每行两个结点x和y&#xf…...

植物源UDP-糖基转移酶及其分子改造-文献精读75

植物源UDP-糖基转移酶及其分子改造 摘要 糖基化能够增加化合物的结构多样性,有效改善水溶性、药理活性和生物利用度,对植物天然产物的药物开发至关重要。UDP-糖基转移酶(UGTs)能够催化糖基从活化的核苷酸糖供体转移到受体形成糖苷键,植物中天然产物的糖基化修饰主要通过UGTs实…...

Redis中String 的底层实现是什么?

Redis中String 的底层实现是什么&#xff1f; Redis 是基于 C 语言编写的&#xff0c;但 Redis 的 String 类型的底层实现并不是 C 语言中的字符串&#xff08;即以空字符 \0 结尾的字符数组&#xff09;&#xff0c;而是自己编写了 SDS&#xff08;Simple Dynamic String&…...

像mysql一样查询es

先简单介绍一下这个sql查询&#xff0c;因为社区一直反馈这个Query DSL 实在是太难用了。大家可以感受一下下面这个es的查询。 GET /my_index/_search { “query”: { “bool”: { “must”: [ { “match”: { “title”: “search” } }, { “bool”: { “should”: [ { “te…...

SpringBoot中@Validated或@Valid注解校验的使用

文章目录 SpringBoot中Validated或Valid注解校验的使用1. 添加依赖2. 使用示例准备2-1 测试示例用到的类2-2 实体Dto&#xff0c;加入校验注解2-2 Controller 3. 示例测试4. Valid 和 Validated注解详解4-1 常用规则注解4-2 分组验证4-2-1 示例准备4-2-2 Controller接口4-2-3 P…...

HashMap为什么线程不安全?

一、Put操作&#xff08;数据覆盖&#xff09; HashMap底层是基于数组 链表&#xff08;在 Java 8 以后&#xff0c;当链表长度超过一定阈值时会转换为红黑树&#xff09;的数据结构。在多线程环境下&#xff0c;当多个线程同时对HashMap进行put操作时&#xff0c;可下面这种…...

类加载器及反射

目录 1.类加载器 1.1类加载【理解】 1.2类加载器【理解】 1.2.1类加载器的作用 1.2.2JVM的类加载机制 1.2.3Java中的内置类加载器 1.2.4ClassLoader 中的两个方法 2.反射 2.1反射的概述【理解】 2.2获取Class类对象的三种方式【应用】 2.2.1三种方式分类 2.2.2示例…...

aws boto3 下载文件

起因&#xff1a;有下载 aws s3 需求&#xff0c;但只有web 登录账号&#xff0c;有 id 用户名 密码&#xff0c;没有 boto3 的 key ID 经过分析&#xff0c;发现网页版有个地址会返回临时 keyID&#xff0c;playwright 模拟登录&#xff0c;用 page.on 监测返回数据&#xff…...

3DDFA-V3——基于人脸分割几何信息指导下的三维人脸重建

1. 研究背景 从二维图像中重建三维人脸是计算机视觉研究的一项关键任务。在虚拟现实、医疗美容、计算机生成图像等领域中&#xff0c;研究人员通常依赖三维可变形模型&#xff08;3DMM&#xff09;进行人脸重建&#xff0c;以定位面部特征和捕捉表情。然而&#xff0c;现有的方…...

求串长(不使用任何字符串库函数)

问题描述 编写一个程序&#xff0c;输入一个字符串&#xff0c;输出串的长度。 要求&#xff1a; &#xff08;1&#xff09;字符串长度不超过100个字符。 &#xff08;2&#xff09;不使用任何字符串库函数&#xff0c;建议使用堆串存储结构。 输入描述 输入一个字符串。 …...

第02章 MySQL环境搭建

一、MySQL的卸载 如果安装mysql时出现问题&#xff0c;则需要将mysql卸载干净再重新安装。如果卸载不干净&#xff0c;仍然会报错安装不成功。 步骤1&#xff1a;停止MySQL服务 在卸载之前&#xff0c;先停止MySQL8.0的服务。按键盘上的“Ctrl Alt Delete”组合键&#xff0…...

linux系统编程 man查看manual.stat

获取文件属性&#xff0c;&#xff08;从inode结构体中获取&#xff09; stat/lstat 函数 int stat(const char *path, struct stat *buf); 参数&#xff1a; path&#xff1a; 文件路径 buf&#xff1a;&#xff08;传出参数&#xff09; 存放文件属性&#xff0c;inode结构体…...

从网络到缓存:在Android中高效管理图片加载

文章目录 在Android应用中实现图片缓存和下载项目结构使用 代码解析关键功能解析1. 图片加载方法2. 下载图片3. 保存图片到缓存4. 文件名提取 总结 首先我们需要在配置AndroidManifest.xml里面添加 <uses-permission android:name"android.permission.INTERNET" …...

【数据结构】链表详解:数据节点的链接原理

链表&#xff08;Linked List&#xff09;是一种基础的数据结构&#xff0c;是程序设计中用来存储数据的典型方法之一。链表特别适合插入和删除操作频繁的场景&#xff0c;是了解数据结构和算法的基础。本文将从零开始&#xff0c;带大家了解链表的底层原理、类型&#xff08;单…...

使用AWS Redshift从AWS MSK中读取数据

Amazon Redshift 流式摄取的目的是简化将流式数据直接从流式服务摄取到 Amazon Redshift 或 Amazon Redshift Serverless 的过程。 官方文档[1]中有详细步骤。用unauthenticated, IAM 的方式均可以进行连接&#xff0c;只不过使用的是不同端口&#xff1a;9092或者9098 [1] h…...

从0开始学统计-数据类别与测量层次

数据分析前&#xff0c;我们首先要弄清楚数据的分类。数据并不仅仅是一堆数字和文字&#xff0c;它们实际上代表了我们看待事物属性的不同视角。从最宽泛的角度出发&#xff0c;我们可以将数据划分为定量&#xff08;比如用数字表示&#xff09;或者定性&#xff08;例如&#…...

使用AIM对SAP PO核心指标的自动化巡检监控

一、背景 由于SAP PO系统维护成本较高&#xff0c;各类型异常报错等都需要人员进行时刻监控和响应&#xff0c;遂由AIM平台进行自动化巡检SAP PO的各指标&#xff0c;然后告警通知用户&#xff0c;节省维护成本和提高工作效率 二、核心指标监控 SAP PO失败消息 适用于S…...

C++——unordered_map和unordered_set的封装

unordered_map和unordered_set的底层结构用到的都是在哈希表模拟实现中的哈希桶的实现方式&#xff0c;哈希桶的具体实现我已经在哈希表的模拟实现里做过详细的介绍&#xff0c;这边会引用里面的代码进行改造和封装&#xff0c;同时为了方便操作&#xff0c;同样我采用二倍扩容…...

微信小程序scroll-view吸顶css样式化表格的表头及iOS上下滑动表头的颜色覆盖、z-index应用及性能分析

微信小程序scroll-view吸顶css样式化表格的表头及iOS上下滑动表头的颜色覆盖、z-index应用及性能分析 目录 微信小程序scroll-view吸顶css样式化表格的表头及iOS上下滑动表头的颜色覆盖、z-index应用及性能分析 1、iOS在scroll-view内部上下滑动吸顶的现象 正常的上下滑动吸顶…...

【高中数学】数列

等差数列前 n n n 项和性质 公式一&#xff1a; S n n ( a 1 a n ) 2 S_n\frac{n(a_1a_n)}{2} Sn​2n(a1​an​)​ 公式二&#xff1a; S n n a 1 n ( n − 1 ) 2 d S_nna_1\frac{n(n-1)}{2}d Sn​na1​2n(n−1)​d 性质1&#xff1a;等差数列中依次 k k k 项之和 S …...

数字媒体技术基础:AMF(ACES 元数据文件 )

在现代电影和电视制作中&#xff0c;色彩管理变得越来越重要。ACES&#xff08;Academy Color Encoding System&#xff0c;美国电影艺术与科学学院颜色编码系统&#xff09;是一个广泛采用的色彩管理和交换系统&#xff0c;旨在解决不同设备、软件和工作流程之间的色彩不一致问…...

Apache Dubbo (RPC框架)

本文参考官方文档&#xff1a;Apache Dubbo 1. Dubbo 简介与核心功能 Apache Dubbo 是一个高性能、轻量级的开源Java RPC框架&#xff0c;用于快速开发高性能的服务。它提供了服务的注册、发现、调用、监控等核心功能&#xff0c;以及负载均衡、流量控制、服务降级等高级功能。…...

LeetCode 3226. 使两个整数相等的位更改次数

. - 力扣&#xff08;LeetCode&#xff09; 题目 给你两个正整数 n 和 k。你可以选择 n 的 二进制表示 中任意一个值为 1 的位&#xff0c;并将其改为 0。 返回使得 n 等于 k 所需要的更改次数。如果无法实现&#xff0c;返回 -1。 示例 1&#xff1a; 输入&#xff1a; n …...

面试经典 150 题:189、383

189. 轮转数组 【参考代码】 class Solution { public:void rotate(vector<int>& nums, int k) {int size nums.size();if(1 size){return;}vector<int> temp(size);//k k % size;for(int i0; i<size; i){temp[(i k) % size] nums[i];}nums temp; }…...

Python模拟真人动态生成鼠标滑动路径

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…...

如何压缩pdf文件的大小?5分钟压缩pdf的方法推荐

如何压缩pdf文件的大小&#xff1f;在现代办公和学习中&#xff0c;PDF文件因其稳定性和广泛的兼容性被广泛使用。然而&#xff0c;随着文件内容的增多&#xff0c;制作好的PDF文件常常变得过大&#xff0c;给使用带来了诸多不便。无论是电子邮件附件的发送&#xff0c;还是在线…...