Chinaunix首页 | 论坛 | 博客
  • 博客访问: 32818
  • 博文数量: 27
  • 博客积分: 1080
  • 博客等级: 少尉
  • 技术积分: 220
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-09 10:29
文章分类

全部博文(27)

文章存档

2011年(1)

2010年(15)

2009年(11)

我的朋友

分类: 嵌入式

2010-02-04 13:57:42

volatile顾名思义“易变的,不被优化的”。让我们分析一个例子,看看codewarrior是怎样处理一个volatile和一个非volatile变量.

volatile unsigned char PORTA @0x00;

volatile unsigned char SCS1  @0x16;

unsigned char value;

void main(void){

PORTA = 0x05;            /* PORTA = 00000101 */

PORTA = 0x05;            /* PORTA = 00000101 */

SCS1;

value = 10; 

}

未使用Volatile关键字,编译器将其编译为:

MOV   #5,PORTA

LDA   #10

STA   @value

使用Volatile关键字后编译器将其编译为

MOV   #5,PORTA

MOV   #5,PORTA

LDA   SCS1

LDX   #10

STX   @value

 

这段代码实际上不做任何事,但它很好地表达了优化怎样强烈地影响程序的结果。在main()中连续两次使用语句:PORTA=5,这没有意义,但让我们假设这是正确开发程序所必须.在这两个语句之后,明显地有一条无意义语句SCS1;。让我们看当不使用volatile变量会发生什么。

我们得到了优化过的汇编代码。重复的语句Port A = 5消失了只剩下一句move #5 to Port A。语句SCS1;似乎什么都不做,因此编译器将它消去了。最后,将10加载到累加器并作为值存贮。

使用volatile关键字声明PORTA SCS1,得到的汇编代码没有优化,连续两次在Port A写入数值5,然后将SCS1加载到累加器。最后由于累加器被使用,于是用X寄存器存贮数值10

好了,连续两次用数值5PortA,假设这是需要这样做,但是加载SCS1到累加器有一个很有意义的值。这是串行通信接口SCI需要的,读SCS1寄存器目的是清除任何未决的标志。

 

以下是volatile的作用,想学东西的请耐心看完(转自于)

volatile的本意是“易变的”
由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。比如:

static int i=0;

int main(void)
{
...
while (1)
{
if (i) dosomething();
}
}

/* Interrupt service routine. */
void ISR_2(void)
{
i=1;
}

程序的本意是希望ISR_2中断产生时,在main当中调用dosomething函数,但是,由于编译器判断在main函数里面没有修改过i,因此
可能只执行一次对从i到某寄存器的读操作,然后每次if判断都只使用这个寄存器里面的“i副本”,导致dosomething永远也不会被
调用。如果将将变量加上volatile修饰,则编译器保证对此变量的读写操作都不会被优化(肯定执行)。此例中i也应该如此说明。

一般说来,volatile用在如下的几个地方:

1、中断服务程序中修改的供其它程序检测的变量需要加volatile;

2、多任务环境下各任务间共享的标志应该加volatile;

3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;

另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实
现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。

关键在于两个地方:     

1. 编译器的优化   (请高手帮我看看下面的理解)

在本次线程内, 当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值;
当变量值在本线程里改变时,会同时把变量的新值copy到该寄存器中,以便保持一致
当变量在因别的线程等而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致
当该寄存器在因别的线程等而改变了值,原变量的值不会改变,从而造成应用程序读取的值和实际的变量值不一致

举一个不太准确的例子:
发薪资时,会计每次都把员工叫来登记他们的银行卡号;一次会计为了省事,没有即时登记,用了以前登记的银行卡号;刚好一个员工的银行卡丢了,已挂失该银行卡号;从而造成该员工领不到工资

员工 -- 原始变量地址
银行卡号 -- 原始变量在寄存器的备份


2. 在什么情况下会出现

     1). 并行设备的硬件寄存器(如:状态寄存器)
     2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
     3). 多线程应用中被几个任务共享的变量

阅读(355) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~