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总是与优化有关。编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在哪里使用、在哪里失效。分析结果能够用于常量合并,常量传播等优化,进一步能够死代码消除。但有时这些优化不是程序所须要的,这时能够用volatilekeyword禁止做这些优化,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)软件上的变化,比如对某个变量赋值等。

当增加了keywordvolatile。则表示该变量的值可因上述两种情况而发生变化;即,对软件来说,硬件上变化的值是不可预知的,增加了该keyword,提示编译器每次读取该变量时。都要直接读取该变量地址中的寄存器。保证了数据的正确性。

分享牛人就是的volatilekeyword的更多相关文章

  1. paper 61:计算机视觉领域的一些牛人博客,超有实力的研究机构等的网站链接

    转载出处:blog.csdn.net/carson2005 以下链接是本人整理的关于计算机视觉(ComputerVision, CV)相关领域的网站链接,其中有CV牛人的主页,CV研究小组的主页,CV ...

  2. IT牛人博客

    IT牛人博客,参见:http://blog.csdn.net/freebird_lb/article/details/8210276 团队技术博客 淘宝UED淘宝用户体验团队 淘宝核心系统淘宝核心系统 ...

  3. 转:Java开发牛人十大必备网站

    原文来自于:http://www.importnew.com/7980.html 以下是我收集的Java开发牛人必备的网站.这些网站可以提供信息,以及一些很棒的讲座, 还能解答一般问题.面试问题等.质 ...

  4. 一年三篇IF大于7的牛人告诉你怎么写SCI

    一年三篇IF大于7的牛人告诉你怎么写SCI 1 研究生必备四本 俗话说好记性不如烂笔头,所以一定要首先养成做笔记的好习惯!作为研究生下面这几个本子是必不可少的: 1.实验记录本(包括试验准备本),这当 ...

  5. 一位IT牛人的十年经验之谈

    1.分享第一条经验:“学历代表过去.能力代表现在.学习力代表未来.” 其实这是一个来自国外教育领域的一个研究结果.相信工作过几年.十几年的朋友对这个道理有些体会吧.但我相信这一点也很重要:“重要的道理 ...

  6. 20年硅谷技术牛人到访DataPipeline谈:技术如何与业务平衡发展

    导读:技术人员的常态是“左手支持业务签单,右手提升系统性能”,却经常陷入技术和业务该如何平衡发展的困惑?今天,且听一位硅谷牛人分享他的平衡之道. 以个人名誉申请31个国内外技术和产品专利,中国最佳CT ...

  7. 学习STM32单片机,从菜鸟到牛人就是这样简单(配视频资料)

    我想说,为了学习单片机而去学习单片机的思路不对. 你问,如何系统地入门学习stm32? 本身就是一个错误的问题.假如你会使用8051 , 会写C语言,那么STM32本身并不需要刻意的学习. 你要考虑的 ...

  8. 如何辨别高潜牛人的六个方法,据说源自500强HR

    如果你是一名领导,当老板派下来任务让你招人的时候,你有考虑过怎么招到合适的人么?今天,架构师米洛特意分享一篇优秀的网络文章,据说来自500强的HR,希望对你招人有所帮助. 如何识人是HR及管理者重要的 ...

  9. Java开发牛人十大必备网站

    以下是我收集的Java开发牛人必备的网站.这些网站可以提供信息,以及一些很棒的讲座, 还能解答一般问题.面试问题等.质量是衡量一个网站的关键因素,我个人认为这些网站质量都很好.接下来,我会跟大家分享我 ...

随机推荐

  1. (1)请求web

    用来测试api的例子 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...

  2. (6)java基础知识-基本数据类型、数据类型转换

    一.基本数据类型 基本的数据类型一共有四类八种 1.整型 byte:  1字节 取值范围 -128~127 short: 2字节    取值范围 -32768~32767 int:     4字节 取 ...

  3. 「kuangbin带你飞」专题二十二 区间DP

    layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...

  4. 【NOIP模拟赛】【乱搞AC】【奇技淫巧】【乘法原理】回文串计数

    回文串计数 (calc.pas/calc.c/calc.cpp) [题目描述] 虽然是一名理科生,Mcx常常声称自己是一名真正的文科生.不知为何,他对于背诵总有一种莫名的热爱,这也促使他走向了以记忆量 ...

  5. SpringAop名词解释+基于xml的配置

    1,AOP名词解释 2,AOP演示 (1)导包: (2)准备目标对象 package com.songyan.service; import org.aspectj.lang.ProceedingJo ...

  6. [读书笔记] CSS揭秘-背景与边框

    半透明边框 默认情况下,背景会延伸到边框所在的区域下层.可以通过background-clip属性调整该默认行为. border: 10px solid rgba(0,0,0,.2) backgrou ...

  7. iOS import framework头文件时报错could not build module xxx

    导致这个错误的原因有多种: 1.库的search paths没有设置对. 2.库里面某些头文件找不到. 而导致.h头文件找不到的原因也有多种: (a)search paths没设置对,文件可能换过位置 ...

  8. OPENDJ的安装图文说明

    一. 说明 介绍: opendj是一个ldap服务器 用于存储openam的配置和用户存储信息 准备工具: OpenDJ-3.0.0.zip 二. 安装步骤 a) Linux安装过程 1. 将zip包 ...

  9. Unity Dotween build error

    unity这东西感觉挺坑 在mac上build的时候遇到error IL2CPP error for method 'System.Void DG.Tweening.DOTweenPath::DORe ...

  10. spring aop expression支持多个表达式配置

    <!-- 配置那些类的方法进行事务管理 --> <aop:config> <aop:pointcut id="allServiceMethod" ex ...