现在的位置: 首页 > 综合 > 正文

volatile的使用

2013年10月18日 ⁄ 综合 ⁄ 共 1387字 ⁄ 字号 评论关闭

     这几天老是纠结于这个关键字,啃了些资料,稍微有点体会,就先写下来吧,要深入理解估计需要更深的汇编知识和编译原理方面的知识。

     1. 以下三个是常用到volatile的地方:

        1) 并行设备的硬件寄存器(如:状态寄存器)

2) 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3) 多线程应用中被几个任务共享的变量

     2. volatile的精确定义及解释:

     volatile意为易变的,一个申明为volatile的变量即时告诉编译器这个变量是可以在意想不到的地方被改变,于是编译器就不会去假设这个变量的值,优化器在每次使用这个变量就不会使用保存在寄存器里的备份,而是直接从源地址读取这个变量的值。由上可知,申明为volatile的目的就是告诉编译器每次使用这个变量时都从变量的地址处取值,而这样做的原因是这个变量“可能会被意想不到地改变”。volatile解释为“直接存取原始内存地址”比较合适。

   3. “直接存取原始内存地址”

 一般思维下,我们总是假定程序中使用的变量即是我们定义的那个变量的地址的值,然而在有优化的情况下,实际并不一定是这样的。

       首先来看执行效率,编译器操作寄存器比操作内存要快得多。以下2组指令中,尽管第2组有3条指令,但执行时间依然比第一组更快:

1) inc jiffies ;  2) mov jiffies, %eax; inc %eax; mov %eax, jiffies

于是,出于执行效率的考虑,编译器将优化我们的代码。即,在本线程内,当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中以后,再取变量值时,就直接从寄存器中取值;当变量值在本线程里改变时,会同时把变量的新值copy到该寄存器中,以便保持一致;例如:

 

以上代码,经过编译后将产生如下汇编代码:

 

若i申明为volatile变量,则汇编代码变为:

 

由上面的代码可以看出,当变量i申明为volatile时,每次使用i编译器都将从内存地址里读取i的值;在i不是volatile的情况下,编译器发现a = i; 和 b = i;之间没有对i进行过操作,即假定i的值没有变化,于是直接将寄存器的值赋给b.因此,使用volatile与否的关键在于a = i;和b = i;之间会不会发生使i改变的事件.

4. "意想不到的改变"

  通过3.可知,当一个变量可能被意想不到地改变时,则应该被申明为volatile型,那么,什么情况下变量会被意想不到地改变呢?通常的可能有三种:

1)  若变量为硬件状态寄存器,则外部硬件可能会改变变量的值;

2)  若在执行完a = i;之后发生中断,而中断服务程序中又使用并改变了i的值;

3)  若在执行到a = i;之后,本线程的时间片用完,调度程序调度新的线程执行,而新的线程又改变了i的值;

4)  若系统为多处理器,在一个处理器执行完a=i时,另一个处理器修改了i的值.

以上三种情况分别对应1的结论里的1),2),3)条。

 

 

抱歉!评论已关闭.