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

Linux | C语言中volatile关键字的理解

目录

前言

一、代码引入

二、现象解释

三、具体引用


前言

        本章主要讲解介绍volatile关键的作用与使用场合;深刻理解volatile关键字;本文你需要有信号相关的基础知识;

Linux | 信号-CSDN博客

一、代码引入

        首先,我们来查看下面这段代码;

#include <iostream>
#include <signal.h>// 定义全局变量
int flag = 1;void handler(int signum)
{(void)(signum); // 防止编译器警告std::cout << "change before flag:" << flag << std::endl;flag = 0;std::cout << "change after flag:" << flag << std::endl;
}int main()
{// 对2号信号捕捉signal(SIGINT, handler);// 死循环while(flag);std::cout << "run here..." << std::endl;return 0;
}

        当我们发送2号信号时,全局变量flag被改为了0,然后循环条件不满足,打印 run here 后退出;我们运行查看结果是否满足我们预期结果;如下所示;

        第一个红色框起来的是我们编译程序所用指令;第二个红色框起来的是当我们按下 ctrl + c 发送2号信号时,程序如我么预期所料;

        接下来,我们来介绍以下 gcc/g++ 的几个编译选项;如下图所示;

        -O1、-O2、-O3分别为编译时三个不同等级的优化,其中优化程度由低到高,我们选择最高等级,再次编译运行代码;如下所示;

        神奇的一幕发生了,我们发现我们无论按多少次 ctrl + c 都无法退出程序,我们发送2号信号,也被处理了,我们的全局变量flag不是被置为0了吗?为什么还是没有办法退出while循环呢?下面我们来仔细讲解这个神奇现象;

二、现象解释

        实际上,这就是跟我们的编译器优化有关,我们把视角拉到代码中;如下图所示;

        我们的while循环判断分为以上三个步骤,而当我们编译时对代码采用 O3 级别的优化时,我们的编译器检测到循环中没有对全局变量flag进行修改,因此直接将上面的步骤优化成了如下所示;

        故即使我们发送2号信号将内存中的flag更改,但是判断时时候,依旧直接判断寄存器中flag的那个值;所以才会看到上述那种神奇现象;

三、具体引用

        我们本文的主角volatile关键字就是为了防止这种编译器过度优化的现象,我们可以在定义flag变量的前面加上一个 volatile关键字,这样可以防止我们的变量flag参与被编译器编译的代码过度优化;

#include <iostream>
#include <signal.h>// 定义全局变量(增加volatile关键字)
volatile int flag = 1;void handler(int signum)
{(void)(signum); // 防止编译器警告std::cout << "change before flag:" << flag << std::endl;flag = 0;std::cout << "change after flag:" << flag << std::endl;
}int main()
{// 对2号信号捕捉signal(SIGINT, handler);// 死循环while(flag);std::cout << "run here..." << std::endl;return 0;
}

        代码几乎完全相同,就加入了一个volatile关键字,避免了这种编译器过度优化现象;

相关文章:

Linux | C语言中volatile关键字的理解

目录 前言 一、代码引入 二、现象解释 三、具体引用 前言 本章主要讲解介绍volatile关键的作用与使用场合&#xff1b;深刻理解volatile关键字&#xff1b;本文你需要有信号相关的基础知识&#xff1b; Linux | 信号-CSDN博客 一、代码引入 首先&#xff0c;我们来查看下面…...

汇编层面有三个主要的操作对象

1.为啥会有addi指令&#xff1f; 在汇编层面有三个主要的操作对象&#xff1a;寄存器&#xff0c;内存&#xff0c;立即数&#xff0c;它们是完全不同&#xff0c;不可以混淆&#xff0c;组织结构也不一样的不同对象&#xff0c;所以不能单纯拿针对寄存器的指令去处理内存和立…...

React中的Redux:简介和实例代码

React是一个流行的JavaScript库&#xff0c;用于构建用户界面。它提供了一种简单而强大的方式来构建交互式的界面。Redux是一个用于管理应用程序状态的JavaScript库。它可以与React一起使用&#xff0c;以帮助管理React应用程序的状态。 引言 在本文中&#xff0c;我们将介绍R…...

Modbus转Profinet网关在金银精炼控制系统中应用案例

金银精炼控制系统中采用Modbus转Profinet网关&#xff08;XD-MDPN100&#xff09;连接1200plc与PID控制阀门进行通讯&#xff0c;通过控制PID阀门的大小来实现温度的恒温控制。这一系统的好处在于它能够提高金银精炼过程的效率和精确度。PID控制阀门可以根据温度的变化实时调整…...

小程序商城免费搭建之java商城 电子商务Spring Cloud+Spring Boot+二次开发+mybatis+MQ+VR全景+b2b2c

1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis 3. 前端框架…...

Rabin加解密算法(python3)

Rabin加解密算法 详细代码如下&#xff1a; # 空空 # dahouzi.cn import random from sympy import isprimedef decrypt_rabin(c, p, q):"""解密 Rabin 密文Args:c (int): 密文p (int): 素数 pq (int): 素数 qReturns:tuple: 解密结果 M1, M2, M3, M4"&q…...

【带头学C++】----- 七、链表 ---- 7.5 学生管理系统(链表--上)

目录 1.main函数设计 2.定义Node节点类型 3.链表插入结点 在main函数中调用插入函数、打印函数 插入结点函数实现&#xff08;头插法&#xff09; 插入结点函数实现&#xff08;尾插法&#xff09; 遍历链表函数实现 4.演示插入、遍历结果 目录 1.main函数设计 2.定义…...

(四)什么是Vite——冷启动时vite做了什么(源码、middlewares)

vite分享ppt&#xff0c;感兴趣的可以下载&#xff1a; ​​​​​​​Vite分享、原理介绍ppt 什么是vite系列目录&#xff1a; &#xff08;一&#xff09;什么是Vite——vite介绍与使用-CSDN博客 &#xff08;二&#xff09;什么是Vite——Vite 和 Webpack 区别&#xff0…...

Docker部署MinIO对象存储服务器结合Cpolar实现远程访问

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远…...

C#入门(1):程序结构、数据类型

一、C#程序结构 第一个C#程序 using System;namespace base_01 {class Program{#region 代码折叠块static void Main(string[] args){//控制台输出Console.WriteLine("Hello World!");Console.Write("C#是微软的编程语言"); //不换行输出//Console.Rea…...

Scala---元组

1、元组定义 与列表一样&#xff0c;与列表不同的是元组可以包含不同类型的元素。元组的值是通过将单个的值包含在圆括号中构成的。 2、创建元组与取值 val tuple new Tuple&#xff08;1&#xff09; 可以使用newval tuple2 Tuple&#xff08;1,2&#xff09; 可以不使…...

【Linux】冯诺依曼体系结构、操作系统、进程概念、进程状态、环境变量、进程地址空间

目录 一、冯诺依曼体系结构二、操作系统(OS)1. 操作系统是什么2. 操作系统如何做管理3. 系统调用和库函数概念 三、进程1. 进程是什么&#xff1f;2. 描述进程-PCB3. 查看进程的方法 四、进程状态1 运行、阻塞和挂起状态2 Linux中的进程状态 五、进程优先级1. 什么是优先级2.查…...

【hive-解决】HiveAccessControlException Permission denied: CREATEFUNCTION

文章目录 一.任务描述二. 解决 一.任务描述 Error while compiling statement: FAILED: HiveAccessControlException Permission denied: Principal [nameroot, typeUSER] does not have following privileges for operation CREATEFUNCTION [ADMIN PRIVILEGE on INPUT, ADMIN…...

内网穿透的应用-通过内网穿透快速搭建公网可访问的Spring Boot接口调试环境

文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…...

解决 uniapp 开发微信小程序 不能使用本地图片作为背景图 问题

参考博文&#xff1a;uniapp微信小程序无法使用本地静态资源图片(背景图在真机不显示)的解决方法_javascript技巧_脚本之家 问题&#xff1a;uniapp 开发微信小程序&#xff0c;当使用本地图片作为 background-image 时&#xff0c;真机无法显示 解决&#xff1a; 方法一&am…...

常用中间件封装思路粗记

MQ 自定义注解 &#xff0c;编写配置类在bean属性初始化SmartInitializingSingleton#afterSingletonsInstantiated后至处理器 去扫描有自定义注解的bean&#xff0c;去创建对应消费者的容器 并启动消费者容器类主要组件DefaultMQPushConsumer SmartInitializingSingleton#afte…...

探索SPI:深入理解原理、源码与应用场景

文章目录 一、初步认识1、概念2、工作原理3、作用场景 二、源码分析1、ServiceLoader结构2、相关字段3、核心方法 三、案例connector连接器小案例1、新建SPI项目2、创建扩展实现项目1-MongoDB3、创建扩展实现项目2-Oracle4、测试 Spring应用1、创建study工程2、创建forlan-test…...

Web3名词解释

Web3名词解释 以太坊 ERC20 Defi去中心化金融 Defi是Decentralized Finance的英文缩写。 简单理解点就是与传统的高度中心化金融体系相比&#xff0c;去中心化金融是通过区块链技术&#xff0c;比如基于区块链技术开发的手机钱包软件&#xff0c;通过智能合约代码以实现去除…...

Vatee万腾外汇市场新力量:vatee科技决策力

在当今数字化时代&#xff0c;Vatee万腾崭露头角&#xff0c;以其强大的科技决策力进军外汇市场&#xff0c;成为该领域的新力量。这一新动向将不仅塑造外汇市场的未来&#xff0c;也展现Vatee科技决策力在金融领域的引领作用。 Vatee万腾带着先进的科技决策力进入外汇市场&…...

【HarmonyOS开发】配置开发工具DevEco Studio

1、下载 注意&#xff1a; 1、安装过程中&#xff0c;一定要自定义安装位置&#xff0c;包比较大&#xff0c;包比较大&#xff0c;包比较大&#xff01;&#xff01;&#xff01; 2、可以将该工具添加到右键中&#xff0c;否则&#xff0c;如果你的项目不是HarmonyOS&#xff…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

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

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

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...