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 */