分享牛人就是的volatilekeyword
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的更多相关文章
- paper 61:计算机视觉领域的一些牛人博客,超有实力的研究机构等的网站链接
转载出处:blog.csdn.net/carson2005 以下链接是本人整理的关于计算机视觉(ComputerVision, CV)相关领域的网站链接,其中有CV牛人的主页,CV研究小组的主页,CV ...
- IT牛人博客
IT牛人博客,参见:http://blog.csdn.net/freebird_lb/article/details/8210276 团队技术博客 淘宝UED淘宝用户体验团队 淘宝核心系统淘宝核心系统 ...
- 转:Java开发牛人十大必备网站
原文来自于:http://www.importnew.com/7980.html 以下是我收集的Java开发牛人必备的网站.这些网站可以提供信息,以及一些很棒的讲座, 还能解答一般问题.面试问题等.质 ...
- 一年三篇IF大于7的牛人告诉你怎么写SCI
一年三篇IF大于7的牛人告诉你怎么写SCI 1 研究生必备四本 俗话说好记性不如烂笔头,所以一定要首先养成做笔记的好习惯!作为研究生下面这几个本子是必不可少的: 1.实验记录本(包括试验准备本),这当 ...
- 一位IT牛人的十年经验之谈
1.分享第一条经验:“学历代表过去.能力代表现在.学习力代表未来.” 其实这是一个来自国外教育领域的一个研究结果.相信工作过几年.十几年的朋友对这个道理有些体会吧.但我相信这一点也很重要:“重要的道理 ...
- 20年硅谷技术牛人到访DataPipeline谈:技术如何与业务平衡发展
导读:技术人员的常态是“左手支持业务签单,右手提升系统性能”,却经常陷入技术和业务该如何平衡发展的困惑?今天,且听一位硅谷牛人分享他的平衡之道. 以个人名誉申请31个国内外技术和产品专利,中国最佳CT ...
- 学习STM32单片机,从菜鸟到牛人就是这样简单(配视频资料)
我想说,为了学习单片机而去学习单片机的思路不对. 你问,如何系统地入门学习stm32? 本身就是一个错误的问题.假如你会使用8051 , 会写C语言,那么STM32本身并不需要刻意的学习. 你要考虑的 ...
- 如何辨别高潜牛人的六个方法,据说源自500强HR
如果你是一名领导,当老板派下来任务让你招人的时候,你有考虑过怎么招到合适的人么?今天,架构师米洛特意分享一篇优秀的网络文章,据说来自500强的HR,希望对你招人有所帮助. 如何识人是HR及管理者重要的 ...
- Java开发牛人十大必备网站
以下是我收集的Java开发牛人必备的网站.这些网站可以提供信息,以及一些很棒的讲座, 还能解答一般问题.面试问题等.质量是衡量一个网站的关键因素,我个人认为这些网站质量都很好.接下来,我会跟大家分享我 ...
随机推荐
- APP专项测试 | 内存及cpu
命令: adb shell dumpsys meminfo packagename 关注点: 1.Native/Dalvik 的 Heap 信息 具体在上面的第一行和第二行,它分别给出的是JNI层和 ...
- jQuery笔记:checkbox
用jQuery操作checkbox时的一点小问题. 勾选checkbox的时候,$("#id").attr("checked")变为"checked& ...
- 模拟【p2239】 螺旋矩阵
顾z 你没有发现两个字里的blog都不一样嘛 qwq 题目描述--->p2239 螺旋矩阵 看到题,很明显,如果直接模拟的话,复杂度为\(O(n^2)\)过不去.(这个复杂度应该不正确,我不会分 ...
- 代理模式(Proxy)--动态代理(CGLIB)
上一篇:代理模式(Proxy)--动态代理(jdk) (1)CGLIB技术是第三方代理技术,可以对任何类生成代理,代理的原则是对目标对象进行继承代理 (2)如果目标对象被final修饰,则无法被CGL ...
- JDBC完整版实现
package songyan.jdbc.test; import java.sql.Connection; import java.sql.DriverManager; import java.sq ...
- 弱电系统标准CAD图例识图讲解
弱电系统标准CAD图例识图讲解 http://www.360doc.com/content/17/0317/16/33642774_637680009.shtml
- Ubuntu下eclipse不能新建java项目 java project的解决办法
在ubuntu系统中,装了eclipse,打开过,后来装了JDK,却不能新建java项目.重装了几遍eclipse也没有用. 原因分析: 之所以新建找不到java项目是因为eclipse有残留文件导致 ...
- JavaScript入门:006—JS函数的定义
JS函数的声明. 声明函数的格式例如以下: function 函数名(參数列表){ //函数语句: return 返回值; } 来看详细的函数声明.1.普通函数 <script type=&qu ...
- 联想台式机启天m4350 启用intel vt-x
在vmware workstations10 64位上安装windows server 2012操作系统时,出现例如以下错误: 已将该虚拟机配置为使用 64 位客户机操作系统.可是,无法运行 64 位 ...
- 关于RBAC(Role-Base Access Control)的理解
基于角色的访问控制(Role-Base Access Control) 有两种正在实践中使用的RBAC访问控制方式:隐式(模糊)的方式和显示(明确)的方式. 今天依旧有大量的软件应用是使用隐式的访问控 ...