实例观察 c 语言中 volatile 的作用

news2025/6/24 17:09:37

volatile 意思是易变的。

在 c 语言中,如果变量被 volatile 修饰,就是告诉编译器这个变量随时都可能发生变化,那么每次读取变量的时候都会到内存中读取。

如果变量没有被 volatile 修饰,并且编译器发现在多次读取变量之间,变量没有被修改,那么编译器可能将变量的值保存到寄存器中,这样在后边访问变量的时候性能会得到提升。但是如果变量以编译器无法识别的方式被修改,那么这个时候将变量的值保存在寄存器中就可能引入问题。

1 volatile 使用场景

(1)硬件寄存器映射的内存地址

在嵌入是开发中,cpld 或者 fpga 中的寄存器可以映射到内存地址,直接通过内存地址来访问这些寄存器。这些寄存器的值可能会因硬件原因发生改变,这种情况是编译器无法识别的,所以需要 volatile 进行修饰。

(2)中断服务程序中会修改的,并且其它线程会访问的变量,需要使用 volatile 进行修饰。

(3)多线程应用中,多个线程共享的变量,需要使用 volatile 进行修饰。

volatile 是对编译器优化的补充。

在接触 volatile 之前,总会想当然的认为读取一个变量的时候就会去内存地址中读取。其实不不然,编译器会进行优化,如果在多次读取变量之间没有发现变量被修改,编译器可能将变量的值保存到寄存器中,这样后边的读取直接从寄存器中读取。从寄存器中读取相对于从内存中读取,性能大大提升。

但是编译器优化也不是万能的,当改变变量的方式,编译器无法识别的时候,那么编译器优化会导致问题。比如上边这 3 中场景,在这些场景下使用的变量,就需要使用 volatile 进行修饰。

2 实例观察有无 volatile 的区别

如下代码中,有一个全局变量 int flag,初始值是 1。

创建了两个线程 t1 和 t2,在 t1 中有一个 while() 循环,当 flag 的值为 1 的时候,循环继续;否则循环退出,并打印 "flag is not 1"。在 t2 中,将 flag 修改成了 0。

(1)int flag 被 volatile 修饰

编译命令:

gcc -O3 volatile.c -g

编译之后运行程序,会看到当 flag 被设置为 0 之后,t1 线程中的循环退出,并且打印了 "flag is not 1"。

(2)int flag 没有被 volatile 修饰

还是使用相同的命令进行编译。

编译之后运行程序,当 flag 被设置为 0 之后,看不到 t1 线程中的循环退出。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

volatile int flag = 1;

void *thread_entry(void *data) {
  while (flag == 1) {
    int tmp = flag;
  }
  printf("flag is not 1\n");
}


void *thread_entry1(void *data) {
  int *p = (int *)data;
  *p = 0;
  printf("after set flag to 0\n");
}


int main() {
  pthread_t t1;
  pthread_create(&t1, NULL, thread_entry, NULL);

  sleep(10);
  pthread_t t2;
  pthread_create(&t2, NULL, thread_entry1, &flag);

  sleep(100);
  return 0;
}

通过上边两个实验,我们可以看出来加 volatile 和不加 volatile 的区别,与前边分析的一致。

我们通过将可执行文件进行反汇编,通过汇编指令来分析加 volatile 和不加 volatile 之间的区别。

有 volatile 修饰:

从汇编指令中可以看出来,while() 循环,在 1248 到 1257 指令之间循环执行,每次执行的时候,都会到内存中读取 flag 的值。

无 volatile 修饰:

从汇编指令可以看出,while() 循环中,编译器只在 1234, 123b 两个指令中从内存中读取数据,然后进行比较,后边直接在 123d 这一条指令进行循环,并不是每次循环都从内存中读取数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1453931.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文搞懂设计模式—观察者模式

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 微信公众号&#xff1a;Java随想录 文章目录 使用场景实现方式Java对观察者模式的支持Guava对观察者模式的支持Spring对观察者模式的支持 优缺点 观察者模式&#xff08;Observer Pattern&#xff09;是一种…

FlashMeeting(基于FFmpeg+openCV)视频语音通讯系统

Web端体验地址&#xff1a;https://download.csdn.net/download/XiBuQiuChong/88805337 客户端下载地址&#xff1a;https://download.csdn.net/download/XiBuQiuChong/88805337 FlashMeeting(基于FFmpegopenCV)是一整套先进的以FFmpegopenCV技术为基础的视频语音通讯系统。利…

linux基础IO【文件操作】

目录 前言&#xff1a; 1.文件理解 2.C语言文件操作 2.1文件打开 2.2文件关闭 2.3文件写入 2.4文件读取 3.系统文件操作 3.1open 3.2close 3.3write 3.4read 4.访问文件本质 前言&#xff1a; 我们在学习文件操作之前先要了解文件的构成&#xff0c;文件 内容 属…

职业性格在求职应聘和跳槽中的作用

性格测试对跳槽者的影响大不大&#xff1f;首先我们要弄清楚两个问题&#xff0c;性格对我们的职业生涯又没有影响&#xff0c;性格测试是什么&#xff0c;职场中有哪些应用&#xff1f;性格可以说从生下来就有了&#xff0c;随着我们的成长&#xff0c;我们的性格也越来越根深…

Stable Diffusion教程——常用插件安装与测试(一)

前言 随着Stable Diffusion不断演进&#xff0c;越来越多的开发者开始涉足插件开发。尽管网络上存在大量教程&#xff0c;但它们通常零散分布&#xff0c;逐个学习和查找非常耗时&#xff0c;使人感觉每天都在劳累思考。这里总结了Stable Diffusion常用的插件安装与测试方法。…

【JavaScript】点击选中和取消

效果图 &#xff08;1&#xff09;选中 &#xff08;2&#xff09;取消选中 实现 <template><div class"qualitityIssues"><div style"display: flex;"><div class"course-area"><div :class"checkoutIndex …

element table 点击按钮 表格滚动条移动

需求场景&#xff1a;表格列数很多的情况下&#xff0c;不想拖拽滚动条查看明细&#xff0c;所以点击按钮直接跳转到对应的位置 代码实现&#xff1a; <template><div><div class "mytable"><el-tableid "testTable"ref "t…

Qt之条件变量QWaitCondition详解(从使用到原理分析全)

QWaitCondition内部实现结构图&#xff1a; 相关系列文章 C之Pimpl惯用法 目录 1.简介 2.示例 2.1.全局配置 2.2.生产者Producer 2.3.消费者Consumer 2.4.测试例子 3.原理分析 3.1.源码介绍 3.2.辅助函数CreateEvent 3.3.辅助函数WaitForSingleObject 3.4.QWaitCo…

计算机网络之网络安全

文章目录 1. 网络安全概述1.1 安全威胁1.1.1 被动攻击1.1.2 主动攻击 1.2 安全服务 2. 密码学与保密性2.1 密码学相关基本概念2.2 对称密钥密码体制2.2.1 DES的加密方法2.2.2.三重DES 2.3 公钥密码体制 3. 报文完整性与鉴别3.1 报文摘要和报文鉴别码3.1.1 报文摘要和报文鉴别码…

基于微信小程序的健身房私教预约系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

模型可视化

模型标题可视化 可视化工具&#xff1a;Graphiz、Netron、ZetaneEngine 7.2.2Graphiz可视化工具 Graphiz是一个由AT&T实验室启动的开源工具包&#xff0c;用于绘制DOT语言脚本描述的图形&#xff0c;使用它可以非常方便地对任何图形进行可视化。 Graphiz的使用步骤包括创…

【ChatIE】论文解读:Zero-Shot Information Extraction via Chatting with ChatGPT

文章目录 介绍ChatIEEntity-Relation Triple Extration (RE)Named Entity Recognition (NER)Event Extraction (EE) 实验结果结论 论文&#xff1a;Zero-Shot Information Extraction via Chatting with ChatGPT 作者&#xff1a;Xiang Wei, Xingyu Cui, Ning Cheng, Xiaobin W…

PyTorch使用Tricks:学习率衰减 !!

文章目录 前言 1、指数衰减 2、固定步长衰减 3、多步长衰减 4、余弦退火衰减 5、自适应学习率衰减 6、自定义函数实现学习率调整&#xff1a;不同层不同的学习率 前言 在训练神经网络时&#xff0c;如果学习率过大&#xff0c;优化算法可能会在最优解附近震荡而无法收敛&#x…

算法刷题:长度最小的子数组

长度最小的子数组 .题目链接题目详情算法原理滑动窗口定义指针进窗口判断出窗口 我的答案 . 题目链接 长度最小的子数组 题目详情 算法原理 滑动窗口 这道题,我们采用滑动窗口的思想来解决,具体步骤如图所示 定义指针 如图所示,两个指针都需要从左往右进行遍历,因此初始值…

AIGC实战——能量模型(Energy-Based Model)

AIGC实战——能量模型 0. 前言1. 能量模型1.1 模型原理1.2 MNIST 数据集1.3 能量函数 2. 使用 Langevin 动力学进行采样2.1 随机梯度 Langevin 动力学2.2 实现 Langevin 采样函数 3. 利用对比散度训练小结系列链接 0. 前言 能量模型 (Energy-based Model, EBM) 是一类常见的生…

食物厨艺展示404错误页面模板源码

食物厨艺展示404错误页面模板源码&#xff0c;HTMLCSSJSCSS,记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;重定向这个界面 蓝奏云&#xff1a;https://wfr.lanzout.com/i3uC71oj52ah…

初识数据库:探索数据的世界

初识数据库&#xff1a;探索数据的世界 1. 什么是数据库&#xff1f;2. 数据库的类型2.1 关系型数据库&#xff08;RDBMS&#xff09;2.2 非关系型数据库&#xff08;NoSQL&#xff09; 3. 为什么使用数据库&#xff1f;4. 如何选择合适的数据库&#xff1f;5. 结语 在信息技术…

ovs和ovn安装

ovn和ovs介绍 ovn架构图 CMS||-----------|-----------| | || OVN/CMS Plugin || | || | || OVN Northbound DB || | || | || ovn-northd || …

设置windows10资源管理器等的边框

Windows10默认状态下&#xff0c;资源管理器、浏览器等没有边框&#xff0c;在打开多个窗口等情况下&#xff0c;想要拖动或选择某个窗口时&#xff0c;不是很好定位到窗口标题栏。 通过&#xff1a;设置&#xff08;可以通过wini组合键打开设置&#xff09;---》个性化 ---》…

第十二章[模块]:12.4:标准库:datetime

一,官方文档: 1,文档地址 datetime --- 基本日期和时间类型 — Python 3.12.2 文档源代码: Lib/datetime.py datetime 模块提供了用于操作日期和时间的类。 在支持日期时间数学运算的同时,实现的关注点更着重于如何能够更有效地解析其属性用于格式化输出和数据操作。 感知型…