Volatile的应用场景
1、当一个变量可能会被意想不到的更新时,要使用volatile来声明该变量,告诉编译器它所修饰的变量的值可能会在任何时刻被意外的更新。
2、语法
volatile int foo;
int volatile foo;
volatile int * foo;
int volatile * foo;
int * volatile foo;
int volatile * volatile foo;
3、场景
1)并行设备的硬件寄存器(如状态寄存器)
假设我们有一个8位的状态寄存器映射在地址0x1234上。系统需要我们一直监测状态寄存器的值,直到它的值不为0为止。通常错误的实现方法是:
UINT1 * ptr = (UINT1 *) 0x1234;
// Wait for register to become non-zero.等待寄存器为非0值
while (*ptr == 0);
// Do something else.作其他事情
汇编代码:
mov ptr, #0x1234
mov a, @ptr
loop bz loop 编译器认为变量值总是不变的,不必要到内存中读取它,使用一个无限循环来结束
正确:
UINT1 volatile * ptr =
(UINT1 volatile *) 0x1234;
对应的汇编代码为:
mov ptr, #0x1234
loop mov a, @ptr
bz loop
2)中断处理程序
中断处理程序经常负责更新一些在主程序中被查询的变量的值。例如,一个串行通讯中断会检测接收到的每一个字节是否为ETX信号(以便来确认一个消息帧的结束标志)。如果其中的一个字节为ETX,中断处理程序就是修改一个全局标志。一个错误的实现方法可能为:
int etx_rcvd = FALSE;
void main()
{
...
while (!ext_rcvd) 访问的是ext_rcvd备份的寄存器中的值
{
// Wait
}
...
}
interrupt void rx_isr(void)
{
...
if (ETX == rx_char)
{
etx_rcvd = TRUE;
}
...
}
3)多线程应用程序
在实时操作系统中,除去队列、管道以及其他调度相关的通讯结构,在两个任务之间采用共享的内存空间(就是全局共享)实现数据的交换仍然是相当常见的方法。当你将一个优先权调度器应用于你的代码时,编译器仍然不知道某一程序段分支选择的实际工作方式以及什么时候某一分支情况会发生。这是因为,另外一个任务修改一个共享的全局变量在概念上通常和前面中断处理程序中提到的情形是一样的。所以,(这种情况下)所有共享的全局变量都要被声明为 volatile。例如:
int cntr;
void task1(void)
{
cntr = 0;
while (cntr == 0)
{
sleep(1);
}
...
}
void task2(void)
{
...
cntr++;
sleep(10);
...
}
4)利用for循环去延时的程序