分享牛人就是的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开发牛人必备的网站.这些网站可以提供信息,以及一些很棒的讲座, 还能解答一般问题.面试问题等.质量是衡量一个网站的关键因素,我个人认为这些网站质量都很好.接下来,我会跟大家分享我 ...
随机推荐
- Ansible 删除多个文件或目录
翻译和转载该网页内容 http://www.mydailytutorials.com/ansible-delete-multiple-files-directories-ansible/ 背景 ans ...
- StringBuffer 清空
几种方法: 方法1: 1 2 3 4 StringBuffer my_StringBuffer = new StringBuffer(); my_StringBuffer.append('hellow ...
- [LOJ6277]数列分块入门 1
题目大意: 给你一个长度为$n(n\leq 50000)$的序列$A$,支持进行以下两种操作: 1.将区间$[l,r]$中所有数加上$c$: 2.询问$A_r$的值.思路: 分块. 对于整块的数据打标 ...
- C++指针、引用知多少?
上午搞了一个小程序,test半天都没有得到想要的结构,原来是递归的时候没有注意的循环的问题,结果直接死循环了.催了...看来当程序出现问题的时候,首先要整理的是算法思路是否有问题,其次是算法的实现,是 ...
- maven配置memcached.jar
由于目前java memcached client没有官方的maven repository可供使用,因此使用时需要手动将其安装到本地repository. java memcached client ...
- Xcode 5 单元测试(二)OCMock和GHUnit
在Xcode 5 单元测试(一)使用XCTest进行单元测试中说了如何在Xcode 5中使用XCTest进行简单的单元测试,本文就来探讨下mock测试和更高级的工具GHUnit. Mock 首先科普下 ...
- JMeter之Ramp-up Period(in seconds)说明(可同时并发)(转载)
Ramp-up Period(in seconds) [1]决定多长时间启动所有线程.如果使用10个线程,ramp-up period是100秒,那么JMeter用100秒使所有10个线程启动并运行. ...
- etcd集群日常维护
配置文件和启动参数说明 命令行 | 配置文件 | 说明 data-dir | ETCD_DATA_DIR | 指定节点的数据存储目录,包括节点ID,集群ID,集群初始化配置,Snapshot文件,若未 ...
- win10 virtualenv
一 创建新虚拟环境 virtualenv appiumenv 二 激活 appiumenv\Scripts\activate 注意是正斜杠,
- cubemap
cubemap 画的时候 是一张一张画 并不是画成 ------- | | | | | | | | | 这样一个位置 而是一 ...