C++中volatile type specifier

volatile:

volatile type specifier和const一样都是c++中的类型修饰符,它和const相对应。一个变量被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必须避免对该变量的优化,即每次都要重新读取该变量的值。

下面的例子可能会帮助我们更好的理解该修饰符的作用:

volatile int a = 0;
int b = a;
......
// 其他代码,并未明确告诉编译器,对 a 进行过操作。
// 也就是说,在这期间变量a的值可能会被修改,但编译器并不知道。
......
int c = a; // a可能已经被修改,但是变量c可能使用的是变量a原来的值

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

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

volatile指针:

跟const一样,volatile也可以用来修饰指针变量,

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

const int *a; //指向常量的指针,底层const
volatile int *b; //指向volatile变量的指针

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

int *const c; //顶层const
int *volatile d;

多线程下的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的改变不同步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值