volatile是一个类型修饰符(type specifier)。它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么使编译器失去大量优化的机会。
一个定义为volatile的变量是说:这变量可能会被意想不到地改变(这种意外不是说该变量有癫痫,自己随便变,而是说可能因为其他程序、线程、硬件、中断等操作,造成对当前程序或线程不可知的改变,比较好理解就是多线程的共享变量,可能随时存在当前线程无法预知的改变),这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
这里涉及到编译器的编译优化:在当前线程内, 当读取一个普通变量时,为提高存取速度,编译器优化时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值;当变量值在本线程里改变时,会同时把变量的新值copy到该寄存器中,以便保持一致。但当变量在因别的线程等而改变了值,当前线程并不会得到通知,当前线程的该寄存器值不会相应改变,从而造成当前线程读取的值和实际的变量值不一致。嗯,就是这样!
下面是volatile变量几个基本应用(转自百度):
1). 并行设备的硬件寄存器(如:状态寄存器) 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 3). 多线程应用中被几个任务共享的变量
然后,我们需要了解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; }