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

这篇具有很好参考价值的文章主要介绍了C/C++ 中 volatile 关键字详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

转载自菜鸟教程【C/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 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 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。例如:

volatile int i=10;
int a = i;
...
// 其他代码,并未明确告诉编译器,对 i 进行过操作
int b = i;

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

#include <stdio.h>
 
void main()
{
    int i = 10;
    int a = i;
 
    printf("i = %d", a);
 
    // 下面汇编语句的作用就是改变内存中 i 的值
    // 但是又不让编译器知道
    __asm {
        mov dword ptr [ebp-4], 20h
    }
 
    int b = i;
    printf("i = %d", b);
}

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

i = 10
i = 32

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

i = 10
i = 10

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

#include <stdio.h>
 
void main()
{
    volatile int i = 10;
    int a = i;
 
    printf("i = %d", a);
    __asm {
        mov dword ptr [ebp-4], 20h
    }
 
    int b = i;
    printf("i = %d", b);
}

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

i = 10
i = 32

这说明这个 volatile 关键字发挥了它的作用。其实不只是内嵌汇编操纵栈"这种方式属于编译无法识别的变量改变,另外更多的可能是多线程并发访问共享变量时,一个线程改变了变量的值,怎样让改变后的值对其它线程 visible。一般说来,volatile用在如下的几个地方:

  • 1) 中断服务程序中修改的供其它程序检测的变量需要加 volatile;
  • 2) 多任务环境下各任务间共享的标志应该加 volatile;
  • 3) 存储器映射的硬件寄存器通常也要加 volatile 说明,因为每次对它的读写都可能由不同意义;

2、volatile 指针

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

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

const char* cpch;
volatile char* vpch;

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

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

char* const pchc;
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 的改变不同步。

原文地址:https://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777432.html文章来源地址https://www.toymoban.com/news/detail-502630.html

到了这里,关于C/C++ 中 volatile 关键字详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C】volatile 关键字

    1)基本概念 const 是C语言的一个。 const 用于告诉编译器相应的变量可能会在程序的控制之外被修改,因此编译器不应该对其进行优化。 声明语法: 作用: 防止编译器优化,确保对变量的每次访问都是实际的读写操作,而不是使用缓存中的值。 用于表示可能会 被异步

    2024年01月22日
    浏览(36)
  • JAVA volatile 关键字

    volatile 是JAVA虚拟机提供的轻量级的同步机制,有三大特性 1、保证可见性  2、不保证原子性  3、禁止指令重排 JMM  JAVA内存模型本身是一种抽象的概念并不真实存在 它描述的是一组规则或规范,提供这组规范定义了程序中各个变量(包括实例变量、静态变量)的访问方式。

    2024年02月13日
    浏览(36)
  • [JAVAee]volatile关键字

    目录 1.volatile的特性 ①保持线程可见性 2.volatile注意事项及适用场景 ①注意事项 ②适用场景 volatile,译为\\\"易变的\\\". 对此我们就可以这样理解,对于被volatile修饰的变量的数值,是容易变化的. 在之前的线程安全文章中,我们有讲解过\\\"可见性\\\",对于线程间的这个特性可能会导致:线程

    2024年02月16日
    浏览(28)
  • C语言volatile关键字

    在C语言中, volatile 是一个类型修饰符,用于告诉编译器对象的值可能会在编译器无法检测到的情况下被改变。这通常发生在以下两种情况: 硬件的输入/输出操作,例如一个设备寄存器的读取或写入。 共享内存的并行程序,其中一个线程修改了一个内存位置,而另一个线程

    2024年02月07日
    浏览(38)
  • 【Java基础】volatile关键字

    关于作者:CSDN内容合伙人、技术专家, 从零开始做过日活千万级APP。 专注于分享各领域原创系列文章 ,擅长java后端、移动开发、人工智能等,希望大家多多支持。 我们继续总结学习Java基础知识,温故知新。 volatile 是一个Java,可以用来修饰变量,volatile也被称为轻

    2024年02月11日
    浏览(32)
  • 浅析Java中volatile关键字

            Java中的volatile用于修饰一个变量,当这个变量被多个线程共享时,这个变量的值如果发生更新,每个线程都能获取到最新的值。volatile在多线程环境下还会禁止指令重排序,确保变量的赋值操作按照代码的顺序执行。需要注意是它不能保证变量操作的

    2024年01月21日
    浏览(36)
  • volatile关键字(轻量级锁)

    目录 一、volatile出现背景 二、JMM概述 2.1、JMM的规定  三、volatile的特性 3.1、可见性  3.1.1、举例说明  3.1.2、总结 3.2、无法保证原子性 3.2.1、举例说明 3.2.2、分析 3.2.3、使用volatile对原子性测试  3.2.4、使用锁机制  3.2.5、总结 3.3、禁止指令重排序  四、volatile的内存语义 4

    2024年02月15日
    浏览(31)
  • Java中的volatile关键字实现原理

    在并发编程中,线程之间的可见性问题是非常重要的一项难题。Java中提供了一种解决并发可见性问题的机制,即volatile。 在本文中,我们将会讲解Java中volatile的实现原理,为什么它能够保证可见性,以及背后的实现原理涉及到的内存屏障和JVM屏障等内容。在学习

    2023年04月27日
    浏览(34)
  • Java面试题:请谈谈Java中的volatile关键字?

    在Java中,volatile是一种特殊的修饰符,用于确保多线程环境下的变量 可见性和顺序性 。当一个变量被声明为volatile时,它可以确保以下两点: 内存可见性 :当一个线程修改了一个volatile变量的值,其他线程会立即看到这个改变。这是因为volatile会禁止CPU缓存和编

    2024年04月23日
    浏览(44)
  • static,const,volatile,extern,register关键字深入解析

    ✅作者简介:嵌入式入坑者,与大家一起加油,希望文章能够帮助各位!!!! 📃个人主页:@rivencode的个人主页 🔥系列专栏:玩转C语言 💬保持学习、保持热爱、认真分享、一起进步!! 我们都知道一个源文件要生成我们计算机课执行的文件要经过: 源文件(test.c)—预编

    2023年04月08日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包