1.volatile
维基百科
-
volatile关键字用来阻止(伪)编译器认为的无法“被代码本身”改变的代码(变量/对象)进行优化。如在C语言中,
volatile关键字可以用来提醒编译器它后面所定义的变量随时有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。 -
在C语言中,编译器会根据你的代码进行优化,而
volatile
最直接的就是,告诉编译器不要优化这一个变量的运算过程。
2.volatile
的优点
- 优点:防止编译器对变量进行优化。
- 为了提高效率,编译将变量值进行缓存,即把变量值从内存中读取进入寄存器中,每次访问变量时直接从寄存器中读取,
volatile
就是告诉编译器不会优化这个变量,这个变量的值每次从内存中读取。
3.关于const
和volatile
同时修改变量
const
和volatile
可以同时修饰变量,语义上不矛盾。const
表示被修饰的变量不能出现在赋值符号的左边。volatile
表示使用变量时直接从内存取值。- 所以
const
和volatile
同时修饰变量时互不影响其含义。
4.代码演示
-
编写一个程序,线程间全局变量读写,模块设备初始化成功后进入系统。
-
(1)不使用
volatile
:
main.c
1
2 #include <stdio.h>
3 #include <unistd.h>
4
5 extern const int device_init_flg;
6 extern void device_init();
7
8 int main(void)
9 {
10 device_init();
11
12 while(device_init_flg != 1)
13 {
14 sleep(1);
15 printf("wait device init..., status = %d\n", device_init_flg );
16 }
17
18 printf("device init success...\n");
19
20 printf("system start...\n");
21
22 return 0;
23 }
device.c
1
2 #include <stdio.h>
3 #include <pthread.h>
4 #include <unistd.h>
5
6
7 int device_init_flg = 0;
8
9 void *pthread_func(void *argc)
10 {
11 sleep(5);
12
13 device_init_flg = 1;
14
15 printf("pthread device init status : %d\n", device_init_flg);
16 }
17
18
19 void device_init(void)
20 {
21 pthread_t tid = 0;
22
23 pthread_create(&tid, NULL, pthread_func, NULL);
24 }
不优化编译:
book@www.100ask.org:~/lzg/c$ ./a.out
wait device init..., status = 0
wait device init..., status = 0
wait device init..., status = 0
wait device init..., status = 0
pthread device init status : 1
wait device init..., status = 1
device init success...
system start...
结果达到预期,主次线程间device_init_flg
变量数值保持一致。
下面我们来增加 -O3
选项来进行优化编译:
book@www.100ask.org:~/lzg/c$ gcc -O3 main.c device.c -lpthread
book@www.100ask.org:~/lzg/c$ ./a.out
wait device init..., status = 0
wait device init..., status = 0
wait device init..., status = 0
wait device init..., status = 0
pthread device init status : 1
wait device init..., status = 0
wait device init..., status = 0
wait device init..., status = 0
wait device init..., status = 0
wait device init..., status = 0
^C
结果发现,次线程中device_init_flg
变量值已经变为1了,但主线程中的device_init_flg
变量值仍为0,并没有同步。这是因为编译时增加了优化等级处理,在main.c
文件中,device_init_flg
变量没有进行赋值,编译器就将device_init_flg
的数值存储到寄存器中进行缓存,每次都到寄存器中读取device_init_flg
的值。
- 下面我们对
device_init_flg
变量增加volatile
进行修饰。
main.c
2 #include <stdio.h>
3 #include <unistd.h>
4
5 extern const volatile int device_init_flg;
device.c
1
2 #include <stdio.h>
3 #include <pthread.h>
4 #include <unistd.h>
5
6
7 volatile int device_init_flg = 0;
同样采用-O3
选项进行优化编译:
book@www.100ask.org:~/lzg/c$ gcc -O3 main.c device.c -lpthread
book@www.100ask.org:~/lzg/c$ ./a.out
wait device init..., status = 0
wait device init..., status = 0
wait device init..., status = 0
wait device init..., status = 0
pthread device init status : 1
wait device init..., status = 1
device init success...
system start...
结果发现device_init_flg
变量并没有被优化,主次线程中数据保持一致。