`

关于volatile类型的变量

阅读更多
转自CSDN上面看到的一段话,个人感觉解释的比较透彻易懂,拿来学习一下:
http://topic.csdn.net/t/20060106/23/4502657.html

volatile仅仅一个不起眼的关键字  
尽管C和C++标准对于线程都明显的“保持沉默”,但它们以volatile关键字的形式,确实为多线程保留了一点特权。  

就象大家更熟悉的const一样,volatile是一个类型修饰符(type   modifier)。它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会。下面我们来一个个说明。  

考虑下面的代码:  

class   Gadget  
{  
public:  
void   Wait()  
{  
while   (!flag_)  
{  
Sleep(1000);   //   sleeps   for   1000   milliseconds  
}  
}  
void   Wakeup()  
{  
flag_   =   true;  
}  
...  
private:  
bool   flag_;  
};  

上面代码中Gadget::Wait的目的是每过一秒钟去检查一下flag_成员变量,当flag_被另一个线程设为true时,该函数才会返回。至少这是程序作者的意图,然而,这个Wait函数是错误的。  
假设编译器发现Sleep(1000)是调用一个外部的库函数,它不会改变成员变量flag_,那么编译器就可以断定它可以把flag_缓存在寄存器中,以后可以访问该寄存器来代替访问较慢的主板上的内存。这对于单线程代码来说是一个很好的优化,但是在现在这种情况下,它破坏了程序的正确性:当你调用了某个Gadget的Wait函数后,即使另一个线程调用了Wakeup,Wait还是会一直循环下去。这是因为flag_的改变没有反映到缓存它的寄存器中去。编译器的优化未免有点太……乐观了。  

在大多数情况下,把变量缓存在寄存器中是一个非常有价值的优化方法,如果不用的话很可惜。C和C++给你提供了显式禁用这种缓存优化的机会。如果你声明变量是使用了volatile修饰符,编译器就不会把这个变量缓存在寄存器里——每次访问都将去存取变量在内存中的实际位置。这样你要对Gadget的Wait/Wakeup做的修改就是给flag_加上正确的修饰:  

class   Gadget  
{  
public:  
...   as   above   ...  
private:  
volatile   bool   flag_;  
};  

大多数关于volatile的原理和用法的解释就到此为止,并且建议你用volatile修饰在多个线程中使用的原生类型变量。然而,你可以用volatile做更多的事,因为它是神奇的C++类型系统的一部分。  
把volatile用于自定义类型  
volatile修饰不仅可以用于原生类型,也可以用于自定义类型。这时候,volatile修饰方式类似于const(你也可以对一个类型同时使用const和volatile)。  

与const不同,volatile的作用对于原生类型和自定义类型是有区别的。就是说,原生类型有volatile修饰时,仍然支持它们的各种操作(加、乘、赋值等等),然而对于class来说,就不是这样。举例来说,你可以把一个非volatile的int的值赋给一个volatile的int,但是你不能把一个非volatile的对象赋给一个volatile对象。  
分享到:
评论

相关推荐

    volatile变量详解

    volatile 变量是一种特殊类型的变量,关键字 volatile 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。简单地说就是防止编译器对代码进行优化。 volatile 变量的作用是防止编译器对...

    java入门教程:数据类型_Java理论与实践如何正确使用Volatile变量.docx

    java入门教程:数据类型_Java理论与实践如何正确使用Volatile变量.docx

    关于volatile关键字的说明以及测试

    volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如 操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行 优化,从而可以提供...

    const和volatile分析

    在C++编程语言中,`const`和`volatile`是两个非常重要的关键字,它们用于修饰变量,赋予变量特殊的属性。这两个关键字在理解程序的行为、内存模型以及多线程编程中起到至关重要的作用。在此,我们将深入探讨`const`...

    extern_volatile等修饰符的用法

    在C++语言中,extern、volatile、const、static等修饰符都是非常重要的,它们可以影响变量的存储方式、生命周期和访问权限等。本文将详细介绍这些修饰符的用法和特点。 一、const修饰符 const修饰符用于声明常量,...

    CC++ Volatile关键词剖析1

    `volatile`是一个类型修饰符,用于告诉编译器某个变量的值可能会被程序外部的某些因素(如硬件中断、多线程环境或其他异步事件)改变,因此编译器不能对这个变量进行优化,每次访问时都需要从内存读取最新值。...

    深入理解 volatile 关键字.doc

    其意思是说,变量不能和其他变量一起参与判断,无论其他变量是否是volatile类型的变量。例如if(a && b)这个判断就无法满足volatile的第二条规则,会发生线程安全问题,即使这两个变量都是volatile类型的变量。 ...

    C++ volatile 详解

    它是一种类型修饰符,用来声明可以被某些编译器未知的因素更改的类型变量,例如操作系统、硬件或者其它线程等。 为什么用 volatile? volatile 关键字的主要作用是防止编译器对代码进行过度优化,以确保变量的值...

    多方面解读Java中的volatile关键字.rar

    3. **原子性**:`volatile`不具备原子性,这意味着对`volatile`变量的非基本类型(如数组或对象引用)的赋值操作可能不是原子的。例如,如果你有一个`volatile`整型变量,并且两个线程同时对其进行加一操作,结果...

    Volatile的正确使用1

    比如,对于`long`和`double`类型的变量,即使使用`volatile`,它们的赋值操作也不是原子的,需要两个机器字来存储,因此可能出现中间状态,导致线程安全问题。但对其他基础类型(如`int`)的简单读写操作,由于Java...

    变量的存储类型.zip

    在这个“变量的存储类型.zip”压缩包中,包含了一些与C++编程相关的源代码文件,如StdAfx.cpp、变量的存储类型.cpp等,它们可能涉及到对变量不同存储类型的探讨和示例。 首先,我们要了解变量有几种基本的存储类型...

    (*(volatile unsigned long *)详解

    这是一种强制类型转换,强制将`0xE0028000`这个地址转换成`volatile unsigned long *`类型的指针。这里的`volatile`关键字是什么意思呢? `volatile`关键字是告诉编译器,这个变量可能会被其他程序或者硬件修改,...

    Java 80 道面试题及答案.docx

    volatile 变量提供顺序和可见性保证,例如,JVM 或者 JIT为了获得更好的性能会对语句重排序,但是 volatile 类型变量即使在没有同步块的情况下赋值也不会与其他语句重排序。volatile 提供 happens-before 的保证,...

    volatile使用详解

    volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对...

    深入讲解C语言编程中volatile修饰符的作用

    因此,对于需要原子操作的情况,`volatile`是不够的,还需要额外的同步机制,如`atomic_t`类型或锁机制。 `volatile`的使用需要注意,虽然它可以防止编译器优化,但并不能防止其他层面的优化,比如链接器的优化。在...

    Java 80道面试题和答案.docx

    3. **非原子操作与原子操作**:在Java中,`long`和`double`类型的非`volatile`变量的读写操作不是原子的,可能会导致数据不一致。然而,对于`volatile`修饰的`long`和`double`变量,其读写操作是原子的,这意味着...

    java里的volatile关键字详解

    3. 有序性:Java语言提供了volatile 和synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized是由“一个变量在同一个时刻只允许一条线程对其进行...

    c++常量与变量基本知识

    浮点类型变量顾名思义,浮点类型变量是用来存储带有小数的实数的。C 语言中有三种不同的浮点类型,以下是对这三种不同类型的声明示例:float Amount; /*单精度型*/double BigAmount; /*双精度型*/long double ...

    关于Java变量的可见性问题Java开发Java经验技巧共

    此外,了解变量可见性也有助于理解和解决多线程环境中的并发问题,如通过使用volatile关键字确保多线程环境下的变量可见性。 总的来说,Java变量的可见性是编程实践中不可或缺的一部分,熟练掌握这一概念能够帮助...

Global site tag (gtag.js) - Google Analytics