Volatile变量

维基百科,自由的百科全书
跳转至: 导航搜索

程序设计中,尤其是在C语言C++C#Java语言中,使用volatile关键字声明的变量对象通常拥有和优化和(或)多线程相关的特殊属性。通常,volatile关键字用来阻止(伪)编译器对那些它认为变量的值不能“被代码本身”改变的代码上执行任何优化。 在C环境中,volatile关键字的真实定义和适用范围经常被误解,加之C++、C#和Java都从C中神秘地“继承”了volatile,在这些编程语言中,因此这些语言中volatile的用法和语义大相径庭。

C和C++中的volatile[编辑]

在C,以及C++中,volatile关键字的作用[1]

  • 允许访问内存映射设备
  • 允许在setjmplongjmp之间使用变量
  • 允许在信号处理函数中使用sig_atomic_t变量

根据相关的标准(C,C++,POSIX,WIN32)和目前绝大多数实现,对volatile变量的操作并不是原子的,也不能用来为线程建立严格的happens-before关系。volatile关键字就像便携式线程构建一样基本没什么用处[2][3][4][5][6]

C语言中MMIO的例子[编辑]

在这里例子中,代码将foo的值设置为0。然后开始不断地轮询它的值直到它变成255

static int foo;
 
void bar(void) {
    foo = 0;
 
    while (foo != 255)
         ;
}

一个执行优化的编译器会提示没有代码能修改foo的值,并假设它永远都只会是0.因此编译器将用类似下列的无限循环替换函数体:

void bar_optimized(void) {
    foo = 0;
 
    while (true)
         ;
}

但是,foo可能指向一个随时都能被计算机系统其他部分修改的地址,例如一个连接到中央处理器的设备的硬體暫存器,上面的代码永远检测不到这样的修改。如果不使用volatile关键字,编译器将假设当前程序是系统中唯一能改变这个值部分(这是到目前为止最广泛的一种情况)。 为了阻止编译器像上面那样优化代码,需要使用volatile关键字:

static volatile int foo;
 
void bar (void) {
    foo = 0;
 
    while (foo != 255)
        ;
}

这样修改以后循环条件就不会被优化掉,当值改变的时候系统将会检测到。

C语言中的优化对比[编辑]

下面的C程序和后面的汇编代码展示了volatile关键字如何影响编译器的输出。这里使用的编译器是GCC。

Java中的volatile[编辑]

Java也支持volatile关键字,但它被用于其他不同的用途。当volatile用于一个作用域时,Java保证如下:

  1. (适用于Java所有版本)读和写一个volatile变量有全局的排序。也就是说每个线程访问一个volatile作用域时会在继续执行之前读取它的当前值,而不是(可能)使用一个缓存的值。(但是并不保证经常读写volatile作用域时读和写的相对顺序,也就是说通常这并不是有用的线程构建)。
  2. (适用于Java5及其之后的版本)volatile的读和写建立了一个happens-before关系,类似于申请和释放一个互斥锁[7]

使用volatile会比使用更快,但是在一些情况下它不能工作。volatile使用范围在Java5中得到了扩展,特别是双重检查锁定现在能够正确工作[8]

Ada中的volatile[编辑]

Ada中,比起关键字,Volatile标记更像是一种指令。“对于volatile对象而言,所有读和更新都会作为一个整体直接执行到内存”[9]

参考[编辑]

  1. ^ Publication on C++ standards committee website; http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2016.html
  2. ^ Publication on C++ standards committee website; http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2016.html
  3. ^ Volatile Keyword In Visual C++; http://msdn2.microsoft.com/en-us/library/12a04hfd.aspx
  4. ^ Linux Kernel Documentation - Why the "volatile" type class should not be used; http://kernel.org/doc/Documentation/volatile-considered-harmful.txt
  5. ^ Volatile: Almost Useless for Multi-Threaded Programming (Intel Software Network); http://softwareblogs.intel.com/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/
  6. ^ C++ and the Perils of Double-Checked Locking; http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
  7. ^ Section 17.4.4: Synchronization Order The Java Language Specification, 3rd Edition. Sun Microsystems. 2005 [2010-11-22]. 
  8. ^ Neil Coffey. Double-checked Locking (DCL) and how to fix it. Javamex. [2009-09-19]. 
  9. ^ "C.6 Shared Variable Control" Ada Reference Manual. ISO. 2005 [2010-05-04]. 

外部链接[编辑]