volatile

volatile是一个类型修饰符。它是被设计用来修饰被不同线程访问和修改的变量。

volatile的作用:作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。它表明修饰的变量可能会被意料不到的改变。
读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中,以后再读取变量值时,就直接从存储器中取值。当变量值在本线程改变时,会同时copy到该寄存器中,以便保持一致。当别的线程等改变了值,该寄存器不会相应改变,从而造成应用程序读取的值和实际的不一致。volatile就可以应付这种情况。
 
问题1:一个参数既可以是const还可以是volatile吗?为什么?
答:可以。const含义为”请做为常量使用“,但并非”肯定是个常量“;volatile含义为”这个值可能随时变掉“,而并非”你可以修改这个值“。
例如
int n = 9;
const int *pn = &n;

 

 
pn不能直接修改,但是可以修改n,pn指向也就会变化。
 
另外一个例子在嵌入式系统中比较常见。很多嵌入式系统允许我们访问外部寄存器,该寄存器的地址可能是0x0018,该寄存器的最低位可能表示设备状态,1为忙碌,0为空闲。
#define GET_REG_VALUE(reg) (*reg) /* get register value */
const unsigned char *STATUS_REG = 0x0018; /* status register */
const unsigned char STATUS_BUSY = 0x01; /* busy bit */
while (GET_REG_VALUE(STATUS_REG) & STATUS_BUSY); /* wait until free */
// do something to operate the device
...

 

 
这段代码很可能会死循环。因为编译器强奸民意的将地址0x0018处的值缓存起来,然后每次while的时候都从缓存中读取。虽然STATUS_REG的值是const unsigned char *,但这仅仅表示STATUS_REG寄存器是个只读寄存器,我们不能够在代码中去写这个寄存器,但并不表示这个寄存器是不能够改变的。硬件完成了它的任务之后,就会把状态设置成空闲,因此该寄存器的最后一位在我们循环的时候很可能已经发生了变化。因此在这样的地方,我们要禁止编译器自作聪明的优化,方法如下:
const volatile unsigned char *STATUS_REG = 0x0018; /* status register */
posted on 2015-03-26 14:02  zjzazym  阅读(148)  评论(0编辑  收藏  举报