volatile的用法

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个
变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,
而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量

回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的元素,所用这些都要求volatile变量。不会用volatile内容将会带来灾难。

假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家
伙是不是直正懂得volatile完全的重要性。
1). 一个参数既可以是const还可以是volatile吗?解释为什么。
2). 一个指针可以是volatile 吗?解释为什么。
3). 下面的函数有什么错误:
int square(volatile int *ptr)
{
return *ptr * *ptr;
}
下面是答案:
1).
是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为我们的软件不应该去修改它

2).
是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
3).
这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一
个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}

由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期
望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}



Volatile
关键字告诉编译器不要持有变量的临时性拷贝。一般用在多线程程序中,以避免在其中一个线程操
作该变量时,将其拷贝入寄存器。请看以下情形:


A线程将变量复制入寄存器,然后进入循环,反复检测寄存器的值是否满足一定条件(它期待B线程�
谋浔淞康闹怠�
在此种情况下,当B线程改变了变量的值时,已改变的值对其在寄存器的值没有影响。所以A线程进
入死循环。

volatile 就是在此种情况下使用。

What does volatile do?

This is probably best explained by comparing the effects that volatile and
synchronized have on a method. volatile is a field modifier, while synchronized
modifies code blocks and methods. So we can specify three variations of a simple
accessor using those two keywords:

int i1; int geti1() {return i1;}volatile int i2;
int geti2() {return i2;} int i3; synchronized int geti3() {return i3;}
geti1() accesses the value currently stored in i1 in the current thread. Threads can
have local copies of variables, and the data does not have to be the same as the data
held in other threads. In particular, another thread may have updated i1 in it's
thread, but the value in the current thread could be different from that updated
value. In fact Java has the idea of a "main" memory, and this is the memory that holds
the current "correct" value for variables. Threads can have their own copy of data for
variables, and the thread copy can be different from the "main" memory. So in fact, it
is possible for the "main" memory to have a value of 1 for i1, for thread1 to have a
value of 2 for i1 and for thread2 to have a value of 3 for i1 if thread1 and thread2
have both updated i1 but those updated value has not yet been propagated to "main"
memory or other threads.

On the other hand, geti2() effectively accesses the value of i2 from "main" memory. A
volatile variable is not allowed to have a local copy of a variable that is different
from the value currently held in "main" memory. Effectively, a variable declared
volatile must have it's data synchronized across all threads, so that whenever you
access or update the variable in any thread, all other threads immediately see the
same value. Of course, it is likely that volatile variables have a higher access and
update overhead than "plain" variables, since the reason threads can have their own
copy of data is for better efficiency.

Well if volatile already synchronizes data across threads, what is synchronized for?
Well there are two differences. Firstly synchronized obtains and releases locks on
monitors which can force only one thread at a time to execute a code block, if both
threads use the same monitor (effectively the same object lock). That's the fairly
well known aspect to synchronized. But synchronized also synchronizes memory. In fact
synchronized synchronizes the whole of thread memory with "main" memory. So executing
geti3() does the following:

The thread acquires the lock on the monitor for object this (assuming the monitor is
unlocked, otherwise the thread waits until the monitor is unlocked).
The thread memory flushes all its variables, i.e. it has all of its variables
effectively read from "main" memory (JVMs can use dirty sets to optimize this so that
only "dirty" variables are flushed, but conceptually this is the same. See section
17.9 of the Java language specification).
The code block is executed (in this case setting the return value to the current value
of i3, which may have just been reset from "main" memory).
(Any changes to variables would normally now be written out to "main" memory, but for
geti3() we have no changes.)
The thread releases the lock on the monitor for object this.
So where volatile only synchronizes the value of one variable between thread memory
and "main" memory, synchronized synchronizes the value of all variables between thread
memory and "main" memory, and locks and releases a monitor to boot. Clearly
synchronized is likely to have more overhead than volatile.



const 和 volatile的区别:

在嵌入式开发中: 
const  声明的为只读变量,程序员不能对其进行修改; 
        函数的参数声明为const时,表明此函数不会对这个参数进行修改, 
        const能提高程序的可读性,对程序的维护有很大的作用。 
        const声明的变量最好在定义的时候就对其赋予初值,不然在后面的程序中是不能改变其的值的。 
    例如: const  int  a = 1; 在后面的程序中,程序员不能在改变a的值,如:a = 2; 
这样是不允许的。 
            const  int *p; 指针P所指向的变量的值不能改变,p的值可以改变; 
            int * const p;  指针p所指向的值可以改变,p的值不能改变, 
          const  int * const p; 指针p指向的值不能改变,p的值也不能改变; 
volatile: 
        在两种特殊的情况下需要使用volatile修饰符:第一种情况涉及到内存映射硬件(memory-mapped hardware,如图形适配器,这类设备对计算机来说就好象是内存的一部分一样),第二种情况涉及到共享内存(shared memory,即被两个以上同时运行的程序所使用的内存)。 
你可以去迅雷上下载《C语言编程常见问题解答》里面有很好的讲述。


转载一段话: 

例如: 
volatile int i=10; 
int a = i; 
... 
//其他代码,并未明确告诉编译器,对i进行过操作 

int b = i; 
   
volatile 指出 i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编 

译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是,由于编译器发现两次从 

i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b中,而不是重新 

从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说vola 

tile可以保证对特殊地址的稳定访问。 
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值