volatile关键字

首先简单介绍一下编译器对代码优化的概念:
编译器优化:在不影响程序结果的状况下,改变程序的执行顺序提升效率
优化级别有:
O0 O1 O2 O3
优先级别越高,优化的越厉害
如何优化?在此介绍volatile,咱们只谈优化的一个方式,就是将频繁使用的变量直接加载到离cpu很近的寄存器中。多线程

咱们先来看以下代码:ide

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int flag=1;
void Handler(int signo){
printf("signo=%d\n",signo);
flag=0;
}
int main(){
signal(2,Handler);
while(flag){}                                                                                                        
}

在不优化的状况下直接进行编译,咱们可预见:程序运行起来,当给这个进程发送二号信号flag值才会变为0使循环结束程序运行结束。
但当用O2使编译器对这个代码进行优化时,就会发现按下ctrl+c发送2号信号时,循环依旧不会中止。这是为何呢?
原来:
在编译器在优化过程当中,若编译器断定某个数据是一个比较高的开销,而后编译器没有检测到有代码修改这个数据,便会把频繁使用的数据放到了寄存器中(while循环频繁使用flag,Handle函数虽对他进行修改可是由内核调用的,编译器并不知道),编译器就可能做出了错误的判断,这时就直接把flag这个值优化到寄存器里了,Handle函数对flag的修改只是改变了内存中的flag并无改变寄存器中的flag,于是while判断时用到寄存器中的flag一直是1.因此循环就结束不了。
为了不这种编译器的错误决措,咱们引入volatile关键字
这个关键字修饰变量就是告诉编译器,这个变量必须每次都从内存中读,不敢直接加载到寄存器中,即volatile的目的就是保持内存可见性函数

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
volatile int flag=1;
void Handler(int signo){
printf("signo=%d\n",signo);
flag=0;
}
int main(){
signal(2,Handler);
while(flag){}                                                                                                        
}

在flag前加上volatile,这时候无论怎么优化flag都是从内存中读取的,一改变他就能够读入新的值,于是这个程序当接收到2信号时就能够正常退出了。优化

volatile要常常使用在多线程中,由于编译器对于多执行流的状况不太会判断,因此volatile常常要使用在多线程来让cpu用的变量都是新的。
线程

与volatile相对的是register,即告诉编译器把这个变量放到寄存器中。
可是这register个关键字不常常用了由于编译器知道什么变量该放什么不应放,会自动优化。code

相关文章
相关标签/搜索