一、先来看一个例子
- 在C/C++中,一个简单的自加操作需要涉及三个步骤:
- 第一步:将值从内存(RAM)中取到寄存器中
- 第二步:在寄存器中将值增加
- 第三步:将增加后的值重新写入内存
#include <stdio.h>
int i = 0;
int main()
{
i++;
return 0;
}
- 上面程序的汇编代码如下所示,因此一个i++对应的操作是:
- 1.把变量i从内存(RAM)加载到寄存器
- 2.把寄存器的值加1
- 3.把寄存器的值写回内存(RAM)
- 因此,如果在多任务/多线程的环境下,两个不同的线程中对同一个变量进行++操作,可能导致变量最终只增加了1。如下图所示:
二、volatile关键字
- 通过上面的例子,现在再来介绍volatile关键字就更加容易了。通过上面我们可以看到,编译器会对变量的操作进行优化,会将RAM(内存)中的值先赋值到寄存器中(寄存器的效率高于RAM),然后在寄存器中进行操作,再写入内存中。但是在多任务/多线程的情况下,这显然会发生错误
- volatile关键字的作用就是:防止编译器进行上面的优化,每次读取数据的时候直接从内存中读,而不是从寄存器中进行读
三、几点注意事项
const与volatile
- const关键字可以和volatile关键字一起使用
- 它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它
指针与volatile
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;
}
四、附加:原子操作