转自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对象。
分享到:
相关推荐
在C语言中,`volatile`是一个类型限定符,用于告知编译器不要对该变量进行优化,因为它可能在任何时候被未知的外部源更改。当一个变量被声明为`volatile`时,编译器会假设它的值可能在任意时间发生变化,因此每次...
### Java入门教程:数据类型与正确使用Volatile变量 #### 概述 在Java编程语言中,`volatile`关键字提供了一种轻量级的同步机制,用于确保共享变量的可见性和一定程度上的线程安全性。相比于传统的锁机制如`...
Volatile是C语言中的一个类型修饰符,用于告诉编译器该变量可能会在程序的控制之外被改变,从而禁止编译器对涉及该变量的代码做优化处理。这种用法在多线程、中断服务程序和硬件访问等场合特别重要。接下来详细说明...
volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如 操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行 优化,从而可以提供...
然而,如果`ptr`指向一个`volatile`类型的变量,那么编译器可能会生成以下代码: ```c int square(volatile int *ptr) { int a, b; a = *ptr; b = *ptr; return a * b; } ``` 如果`ptr`指向的值在两次...
在C++编程语言中,`const`和`volatile`是两个非常重要的关键字,它们用于修饰变量,赋予变量特殊的属性。这两个关键字在理解程序的行为、内存模型以及多线程编程中起到至关重要的作用。在此,我们将深入探讨`const`...
然而,`volatile`关键字能防止特定类型的指令重排,确保在多线程环境下,对`volatile`变量的读写操作遵循一定的顺序。具体来说,如果一个操作发生在`volatile`写操作之前,那么这个操作的效应对于后续的`volatile`读...
`volatile` 是一种类型修饰符,用于声明的变量表示这类变量可能会被某些因素(如操作系统、硬件或其他线程)更改,这些更改是编译器所不知道的。在程序设计中,尤其是在并发编程和硬件交互中,`volatile` 关键字具有...
在C++语言中,extern、volatile、const、static等修饰符都是非常重要的,它们可以影响变量的存储方式、生命周期和访问权限等。本文将详细介绍这些修饰符的用法和特点。 一、const修饰符 const修饰符用于声明常量,...
`volatile`是一个类型修饰符,用于告诉编译器某个变量的值可能会被程序外部的某些因素(如硬件中断、多线程环境或其他异步事件)改变,因此编译器不能对这个变量进行优化,每次访问时都需要从内存读取最新值。...
其意思是说,变量不能和其他变量一起参与判断,无论其他变量是否是volatile类型的变量。例如if(a && b)这个判断就无法满足volatile的第二条规则,会发生线程安全问题,即使这两个变量都是volatile类型的变量。 ...
在实际开发中,`volatile`关键字通常用于标记那些不需要同步块保护的、多个线程共享的、状态标志类型的变量,如线程中断标志、单例模式中的`Singleton`实例等。但需要注意的是,`volatile`关键字并不能保证复合操作...
x86处理器有L1、L2、L3缓存,以及多核之间的缓存一致性协议(如MESI协议),这些机制共同保证了多核环境下volatile变量的正确传播和一致性。 总结来说,volatile关键字通过禁止指令重排序和提供内存可见性,确保了...
例如,如果一个变量是volatile类型的,并且有多个线程同时进行增加操作(如x++),那么这个操作就不是原子性的,可能造成数据的不一致。在这种情况下,仍需要使用`synchronized`关键字或者`java.util.concurrent`...
这意味着当一个线程修改了一个`volatile`变量后,其他线程读取该变量时,不仅能看到该变量的最新值,还能看到在此之前这个线程所做的其他所有操作。 - **非原子性**:需要注意的是,虽然`volatile`关键字提供了可见...
3. **原子性**:`volatile`不具备原子性,这意味着对`volatile`变量的非基本类型(如数组或对象引用)的赋值操作可能不是原子的。例如,如果你有一个`volatile`整型变量,并且两个线程同时对其进行加一操作,结果...
- 当一个变量代表了硬件寄存器的状态时,如果硬件可能会直接修改这个寄存器,则应该将这个变量声明为 `volatile` 类型,以确保读取到的是最新的值。 #### 示例代码解析 考虑以下代码片段: ```c #include int ...
1. **基本概念**:`volatile`是一个类型修饰符,用于声明可能被编译器未知因素更改的变量,这些因素包括但不限于操作系统、硬件或其它线程。 2. **内存与缓存一致性**:`volatile`变量要求在每次获取其值时直接从...