volatile总结
来源:互联网 发布:中国如何注册io域名 编辑:程序博客网 时间:2024/05/01 20:17
volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
volatile的本意是“易变的”,不过翻译成“直接存取原始内存地址”更为合适。“易变”是因为外在因素引起的,象多线程,中断等,并不是因为用volatile修饰了的变量就是“易变”了,假如没有外因,即使用volatile定义,它也不会变化。
使用该关键字的例子如下:
volatile int i = 10;int a = i;... //其他代码,并未明确告诉编译器,对i进行过操作int b = i;
volatile 指出 i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问。一般说来,volatile用在如下的几个地方:
- 像中断处理程序之类的异步进程中修改的供其它程序检测的变量需要加volatile;
- 多任务环境下各任务间共享的标志应该加volatile;
- 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义。
另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),在1中可以通过关中断来实现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。
除了基本类型外,对用户定义类型也可以用volatile类型进行修饰。
注意:可以把一个非volatile int赋给volatile int,但是不能把非volatile对象赋给一个volatile对象。
一个有volatile标识符的类只能访问它接口的子集,一个由类的实现者控制的子集。用户只能用const_cast来获得对类型接口的完全访问。此外,volatile向const一样会从类传递到它的成员。
和 const 修饰词类似,const 有常量指针和指针常量的说法,volatile 也有相应的概念:
修饰由指针指向的对象、数据是 const 或 volatile 的:
const char* cpch; volatile char* vpch;
注意:对于 VC,这个特性实现在 VC 8 之后才是安全的。
指针自身的值——一个代表地址的整数变量,是 const 或 volatile 的:
注意:
(1) 可以把一个非 volatile int 赋给 volatile int,但是不能把非 volatile 对象赋给一个 volatile 对象。
(2) 除了基本类型外,对用户定义类型也可以用 volatile 类型进行修饰。
(3) C++ 中一个有 volatile 标识符的类只能访问它接口的子集,一个由类的实现者控制的子集。用户只能用 const_cast 来获得对类型接口的完全访问。此外, volatile 向 const 一样会从类传递到它的成员。
3) 多线程下的 volatile
有些变量是用 volatile 关键字声明的。当两个线程都要用到某一个变量且该变量的值会被改变时,应该用 volatile 声明,该关键字的作用是防止优化编译器把变量从内存装入 CPU 寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile 的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值,如下:
volatile BOOL bStop = FALSE;
这个关键字是用来设定某个对象的存储位置在内存中,而不是寄存器中。因为一般的对象编译器可能会将其的拷贝放在寄存器中用以加快指令的执行速度,例如下段代码中:
深入
1) 一个参数既可以是const还可以是volatile吗?解释为什么。
是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
2) 一个指针可以是volatile 吗?解释为什么。
是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
3) 下面的函数有什么错误:
int square(volatile int *ptr){ return *ptr * *ptr;}这段代码的目的是用来返指针*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总结
- volatile总结
- Volatile总结
- Volatile用法总结
- volatile用法总结
- volatile用法总结
- java volatile总结
- volatile用法小总结
- volatile关键字用法总结
- java volatile总结
- java volatile关键字总结
- 总结一下java volatile
- java Volatile总结
- transient和volatile总结
- volatile关键字总结
- volatile关键字学习总结
- volatile关键字总结
- Volatile关键字总结
- ESP定理如何判断找出OEP 【OEP脱壳的5种方法】
- 一条SQL条件选择数据库记录(再现非Oracle数据库的脑残的连接操作符号)
- 语音识别 一个超简单的语音听写识别编程
- 用EXP/IMP从高版本数据导出数据导入至低版本数据库实验
- vbox Ubuntu与windows主机实现文件共享
- volatile总结
- 语音识别 微软语音技术SAPI语音编程初步
- 林仕鼎谈架构设计与架构师
- 无监督学习特征--稀疏编码、深度学习、ICA部分代表文献
- OpenCV 初體驗
- Android中全屏或者取消标题栏
- HDU-2026首字母大写
- Linux学习笔记(4)-文件基本操作
- iOS并发编程(二)——NSOperation