C/C++中volatile关键字详解

C/C++ 中 volatile 关键字详解 而且读取的数据立刻被保存。在此段代码中,nMyCounter 的拷贝可能存放到某个寄存器中(循环中,对 nMyCounter 的测试及操作总是对此寄存器中的值进行),但是另外又有段代码执行了这样的操作:nMyCounter -= 1;//等待上面的线程终止,如果bStop不使用volatile申明,那么这个循环将是一个死循环,因为bStop已经读取到了寄存器中,寄存器中bStop的值永远不会变成FALSE,加上volatile,程序在执行时,每次均从内存中读出bStop的值,就不会死循环了。 阅读详情

今天在修改XBase的ConnectionManager时,需要一个连接数组,但因为是多线程访问的,所以每个元素(是一个指针)都可能会发生变化。之前定义volatile一直没有一个系统的了解。这里找了一篇文章,感觉说的很全面

1. 为什么用volatile?

    C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory barrier。这是 BS 在 "The C++ Programming Language" 对 volatile 修饰词的说明:

A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided.

      volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。声明时语法:int volatile vInt; 当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。例如:

1 volatile int i=10;

2 int a = i;

3 ...

4 // 其他代码,并未明确告诉编译器,对 i 进行过操作

5 int b = i;

    volatile 指出 i 是随时可能发生变化的,每次使用它的时候必须从 i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在 b 中。而优化做法是,由于编译器发现两次从 i读数据的代码之间的代码没有对 i 进行过操作,它会自动把上次读的数据放在 b 中。而不是重新从 i 里面读。这样以来,如果 i是一个寄存器变量或者表示一个端口数据就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。注意,在 VC 6 中,一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。下面通过插入汇编代码,测试有无 volatile 关键字,对程序最终代码的影响:

输入下面的代码:

01 #include <stdio.h>

02  

03 void main()

04 {

05     int i = 10;

06     int a = i;

07  

08     printf("i = %d", a);

09  

10     // 下面汇编语句的作用就是改变内存中 i 的值

11     // 但是又不让编译器知道

12     __asm {

13         mov dword ptr [ebp-4], 20h

14     }

15  

16     int b = i;

17     printf("i = %d", b);

18 }

    然后,在 Debug 版本模式运行程序,输出结果如下:

i = 10  
i = 32

    然后,在 Release 版本模式运行程序,输出结果如下:

i = 10  
i = 10

    输出的结果明显表明,Release 模式下,编译器对代码进行了优化,第二次没有输出正确的 i 值。下面,我们把 i 的声明加上 volatile 关键字,看看有什么变化:

01 #include <stdio.h>

02  

03 void main()

04 {

05     volatile int i = 10;

06     int a = i;

07  

08     printf("i = %d", a);

09     __asm {

10         mov dword ptr [ebp-4], 20h

11     }

12  

13     int b = i;

14     printf("i = %d", b);

15 }

    分别在 Debug 和 Release 版本运行程序,输出都是:

i = 10  
i = 32

    这说明这个 volatile 关键字发挥了它的作用。其实不只是“内嵌汇编操纵栈”这种方式属于编译无法识别的变量改变,另外更多的可能是多线程并发访问共享变量时,一个线程改变了变量的值,怎样让改变后的值对其它线程 visible。一般说来,volatile用在如下的几个地方: 
1) 中断服务程序中修改的供其它程序检测的变量需要加volatile; 
2) 多任务环境下各任务间共享的标志应该加volatile; 
3) 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;

2.volatile 指针

    和 const 修饰词类似,const 有常量指针和指针常量的说法,volatile 也有相应的概念:

  • 修饰由指针指向的对象、数据是 const 或 volatile 的:

    1 const char* cpch;

    2 volatile char* vpch;

    注意:对于 VC,这个特性实现在 VC 8 之后才是安全的。

  • 指针自身的值——一个代表地址的整数变量,是 const 或 volatile 的:

    1 char* const pchc;

    2 char* volatile pchv;

    注意:(1) 可以把一个非volatile int赋给volatile int,但是不能把非volatile对象赋给一个volatile对象。

          (2) 除了基本类型外,对用户定义类型也可以用volatile类型进行修饰。 
              (3) C++中一个有volatile标识符的类只能访问它接口的子集,一个由类的实现者控制的子集。用户只能用const_cast来获得对类型接口的完全访问。此外,volatile向const一样会从类传递到它的成员。

3. 多线程下的volatile   

    有些变量是用volatile关键字声明的。当两个线程都要用到某一个变量且该变量的值会被改变时,应该用volatile声明,该关键字的作用是防止优化编译器把变量从内存装入CPU寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值,如下: 

 volatile  BOOL  bStop  =  FALSE;   
   (1) 在一个线程中:   
  while(  !bStop  )  {  ...  }   
  bStop  =  FALSE;   
  return;     
   (2) 在另外一个线程中,要终止上面的线程循环:   
  bStop  =  TRUE;   
  while(  bStop  );  //等待上面的线程终止,如果bStop不使用volatile申明,那么这个循环将是一个死循环,因为bStop已经读取到了寄存器中,寄存器中bStop的值永远不会变成FALSE,加上volatile,程序在执行时,每次均从内存中读出bStop的值,就不会死循环了。 
    这个关键字是用来设定某个对象的存储位置在内存中,而不是寄存器中。因为一般的对象编译器可能会将其的拷贝放在寄存器中用以加快指令的执行速度,例如下段代码中:   
  ...   
  int  nMyCounter  =  0;   
  for(;  nMyCounter<100;nMyCounter++)   
  {   
  ...   
  }   
  ...   
   在此段代码中,nMyCounter的拷贝可能存放到某个寄存器中(循环中,对nMyCounter的测试及操作总是对此寄存器中的值进行),但是另外又有段代码执行了这样的操作:nMyCounter  -=  1;这个操作中,对nMyCounter的改变是对内存中的nMyCounter进行操作,于是出现了这样一个现象:nMyCounter的改变不同步。


C++volatile详解 1. 为什么用volatile?     C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory barrier。这是 BS 在 "The C++ Programming Language" 对 volatile 修饰词的说明: A volatile specifier is a hint to a compiler that a 阅读详情

相关推荐

c/c++ volatile关键字详解

volatile 目录简介用法volatile指针多线程下的应用(我们在并发编程开发中经常会遇到的情况) 最近看boost并发的相关文档,发现这个关键字我没怎么用过,惭愧惭愧,特意学习。 简介 volatile 关键字在c/c++中与const同级用来修饰变量,通常建立语言级别的memory barrier,用他声明的变量可以被某些编译器未知的因素修改,如操作系统,硬件,其他线程等。遇到这个关键字声明的变量,编译器就不在对其进行优化,当使用violatile声明变量的时候,系统总是从他所在的内存空间直接读取

jokerro的博客 1235

C++中的volatile

volatile的本意是“易变的”,volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被寄存。例如: volatile 指出 i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而

whl0071的专栏 1万+

C++中的volatile关键字详解

在C++中,volatile是一个关键字,用于修饰变量,它告诉编译器该变量的值可能会在意料之外的时候被修改。volatile关键字的作用就是告诉编译器,在编译期间不要对该变量进行任何优化,而是在运行时始终从内存中读取该变量的值,并且每次使用该变量都要重新读取,而不是使用之前缓存的值。由于中断是由外部硬件触发的,它可能会在任何时刻发生,因此中断标志位的值可能会在不同的上下文中发生变化。使用volatile关键字可以确保每次检查中断标志位时都会从内存中读取最新的值,而不会使用之前缓存的值。

CyberNova的博客 1268

C++知识篇--volatile关键字

C++知识篇--volatile关键字

仰望星空 5964

GPU核心性能指标

内存科普 CPU缓存分为三类,一级缓存(L1)、二级缓存(L2)和三级缓存(L3)。CPU在实际数据读取中重要的却是一级缓存,因为一级缓存速度最快,二级缓存其次,三级缓存最慢,只是三级缓存的容量最大。 DDR1,DDR2,DDR3内存条(DDR是Double Data Rate双倍速率同步动态随机存储器的英文缩写)就是俗称的一二三代内存条。这三种内存条工艺不同,接口不同,性能不同,互不兼容。要区分它们,也不难。内存条可以用在CPU内存或者GPU显存中。比如 the NVIDIA Tesla M2050 GP

Charles Ren's Tech Blog 2万+

VH6501实战:手把手教你用CANoe脚本精准触发CAN总线干扰(附避坑点)

本文详细介绍了使用VH6501和CANoe脚本精准触发CAN总线干扰的实战技巧,包括触发位置控制、ValidityMask配置和干扰序列设置等关键步骤。通过具体代码示例和常见问题排查指南,帮助工程师避开实际应用中的常见陷阱,提升CAN总线干扰测试的准确性和效率。

weixin_33709219的博客 370

详解C/C++中volatile关键字

一、volatile介绍 volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。下面举例说明。在DSP开发中,经常需要等待某个事件的触发,所以经常会写出这样的程序: 这段...

小白的逆袭 8万+

手把手教你用思岚RPLIDAR C1激光雷达实现简单环境扫描(树莓派4B+Ubuntu22.04)

本文详细介绍了如何在树莓派4B(Ubuntu 22.04系统)上驱动思岚RPLIDAR C1激光雷达,从硬件连接、权限配置、SDK编译到运行示例程序,最终实现环境扫描数据的可视化。通过手把手教程,帮助开发者和爱好者快速上手激光雷达应用,构建简单的环境扫描图。

j2k3l4的博客 1133

【C/C++面试必备】详解C/C++中volatile关键字

一、volatile简介 二、volatile易变的 三、volatile不可优化的 四、volatile顺序执行的 五、volatile与原子性 六、volatile 的作用是什么呢 1.修饰普通变量 2.修饰指针 3.作为函数参数 七、volatile的介绍 八、volatile的含义 1.不会在两个操作之间把volatile变量缓存在寄存器中 2.不做常量合并、常量传播等优化 3.对volatile变量的读写不会被优化掉 九、编译器优化 → C关键字volatile → memory破坏描述符 1.编

森明帮大于黑虎帮的博客 6353

华为MA5626 ONU开局配置实战:从零到业务就绪的完整命令手册

本文详细介绍了华为MA5626 ONU设备的开局配置全流程,包括物理连接、命令行初始化、业务VLAN划分、PoE功能配置及故障排查。通过实战命令手册,帮助网络工程师快速完成从设备上电到业务就绪的完整配置,特别适合FTTB场景部署。

weixin_26934905的博客 561

论文阅读笔记---Deep HDR Video from Sequences with Alternating Exposures

Kalantari N K, Ramamoorthi R. Deep HDR Video from Sequences with Alternating Exposures[C]//Computer Graphics Forum. 2019, 38(2): 193-205. 摘要: 在本文中,提出了一种基于学习的方法来,我们使用两个顺序卷积神经网络(CNN)对整个HDR视频重建过程进...

qq_25283239的博客 1447

【C/C++】volatile关键字详解

摘要:volatile关键字是嵌入式系统开发中的关键工具,用于防止编译器优化变量访问。它确保变量每次从内存读取而非寄存器缓存,适用于硬件寄存器、中断共享变量和多线程环境。典型应用包括内存映射寄存器访问、中断服务程序中的标志变量等。但需注意volatile仅解决编译器优化问题,不提供原子性或处理多核同步问题,需配合其他同步机制使用。正确使用volatile是嵌入式开发的必备技能。

2301_79981403的博客 842

基于Python的房地产评估数据抓取与分析 —— 房价走势与市场报告

在房地产行业中,了解和分析房产价格的变化趋势、各个地区的房价差异以及市场评价报告,可以帮助投资者、购房者以及政策制定者做出更加明智的决策。本文介绍了如何使用Python爬虫技术抓取房地产平台上的房产评估报告、价格走势等数据,并对抓取的数据进行分析。通过这些技术,您可以自动化抓取房地产平台的数据,分析房价走势,获取市场报告,为房地产投资决策提供数据支持。假设我们要从链家网抓取某个房产的价格、房产描述以及历史成交价格,首先需要获取目标房产页面的URL,并发送HTTP请求。伪装为常见浏览器,避免被识别为爬虫。

2201_76125261的博客 847
上一篇: 孤岛危机2通关,看到这篇剧情,太精彩忍不住转了--孤岛危机2详细剧情。
下一篇: 建一支强大的小团队(加长版) by 陈皓
寰子
博客等级 码龄15年 91粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值