您的位置 首页 观点

共享牛人解说的volatile关键字

volatile作用一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器

volatile效果

一个界说为volatile的变量是说这变量或许会被意想不到地改动,这样,编译器就不会去假定这个变量的值了。精确地说便是,优化器在用到这个变量时有必要每次都小心肠从头读取这个变量的值,而不是运用保存在寄存器里的备份。下面是volatile变量的几个比方:
1). 并行设备的硬件寄存器(如:状况寄存器)
2). 一个中止服务子程序中会拜访到的非主动变量(Non-automatic variables)
3). 多线程运用中被几个使命同享的变量
答复不出这个问题的人是不会被雇佣的。我以为这是区别C程序员和嵌入式体系程序员的最基本的问题。嵌入式体系程序员常常同硬件、中止、RTOS等等打交道,所用这些都要求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的原意是“易变的”
由于拜访寄存器的速度要快过RAM,所以编译器一般都会作削减存取外部RAM的优化。比方:
static int i=0;
int main(void)
{

while (1)
{
if (i) dosomething();
}
}

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中则只能依托硬件的杰出规划了。
volatile 的意义
volatile总是与优化有关,编译器有一种技能叫做数据流剖析,剖析程序中的变量在哪里赋值、在哪里运用、在哪里失效,剖析成果能够用于常量兼并,常量传达等优化,进一步能够死代码消除。但有时这些优化不是程序所需求的,这时能够用volatile关键字制止做这些优化,volatile的字面意义是易变的,它有下面的效果:
1 不会在两个***作之间把volatile变量缓存在寄存器中。在多使命、中止、乃至setjmp环境下,变量或许被其他的程序改动,编译器自己无法知道,volatile便是告知编译器这种状况。
2 不做常量兼并、常量传达等优化,所以像下面的代码:
volatile int i = 1;
if (i > 0) …
if的条件不会当作无条件真。
3 对volatile变量的读写不会被优化掉。假设你对一个变量赋值但后边没用到,编译器常常能够省掉那个赋值***作,然而对Memory Mapped IO的处理是不能这样优化的。
前面有人说volatile能够确保对内存操作的原子性,这种说法不大精确,其一,x86需求LOCK前缀才能在SMP下确保原子性,其二,RISC底子不能对内存直接运算,要确保原子性得用其他办法,如atomic_inc。
关于jiffies,它现已声明为volatile变量,我以为直接用jiffies++就能够了,没必要用那种杂乱的方式,由于那样也不能确保原子性。
================================================================================
关键在于两个当地:

1. 编译器的优化 (请高手帮我看看下面的了解)
在本次线程内, 当读取一个变量时,为进步存取速度,编译器优化时有时会先把变量读取到一个寄存器中;今后,再取变量值时,就直接从寄存器中取值;
当变量值在本线程里改动时,会一起把变量的新值copy到该寄存器中,以便保持一致
当变量在因其他线程等而改动了值,该寄存器的值不会相应改动,然后形成运用程序读取的值和实践的变量值不一致
当该寄存器在因其他线程等而改动了值,原变量的值不会改动,然后形成运用程序读取的值和实践的变量值不一致
举一个不太精确的比方:
发薪资时,管帐每次都把职工叫来挂号他们的银行卡号;一次管帐为了省劲,没有即时挂号,用了曾经挂号的银行卡号;刚好一个职工的银行卡丢了,已挂失该银行卡号;然后形成该职工领不到薪酬
职工 -- 原始变量地址
银行卡号 -- 原始变量在寄存器的备份
2. 在什么状况下会呈现(如1楼所说)
1). 并行设备的硬件寄存器(如:状况寄存器)
2). 一个中止服务子程序中会拜访到的非主动变量(Non-automatic variables)
3). 多线程运用中被几个使命同享的变量

弥补: volatile应该解说为“直接存取原始内存地址”比较适宜,“易变的”这种解说几乎有点误导人;
“易变”是由于外在要素引起的,象多线程,中止等,并不是由于用volatile润饰了的变量便是“易变”了,假设没有外因,即运用volatile界说,它也不会改变;
而用volatile界说之后,其实这个变量就不会因外因此改变了,能够放心运用了;我们看看前面那种解说(易变的)是不是在误导人

其他弥补volatile在DSP中的了解:

该单词的意思是可变的,易变的。在DSP中,一些寄存器的值的改变有两种状况:(1)硬件上导致的改变,例如中止、ADC等;(2)软件上的改变,例如对某个变量赋值等。

当加入了关键字volatile,则表明该变量的值可因上述两种状况而发生改变;即,对软件来说,硬件上改变的值是不行预知的,加入了该关键字,提示编译器每次读取该变量时,都要直接读取该变量地址中的寄存器,确保了数据的正确性。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/news/guandian/256616.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部