天天看點

volatile關鍵字

首先簡單介紹一下編譯器對代碼優化的概念:

編譯器優化:在不影響程式結果的情況下,改變程式的執行順序提高效率

優化級别有:

O0 O1 O2 O3

優先級别越高,優化的越厲害

如何優化?在此介紹volatile,我們隻談優化的一個方式,就是将頻繁使用的變量直接加載到離cpu很近的寄存器中。

我們先來看如下代碼:

#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){}                                                                                                        
}
           

繼續閱讀