volatile關鍵字

首先簡單介紹一下編譯器對代碼優化的概念:
編譯器優化:在不影響程序結果的狀況下,改變程序的執行順序提升效率
優化級別有:
O0 O1 O2 O3
優先級別越高,優化的越厲害
如何優化?在此介紹volatile,咱們只談優化的一個方式,就是將頻繁使用的變量直接加載到離cpu很近的寄存器中。markdown

咱們先來看以下代碼:多線程

#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的目的就是保持內存可見性ide

#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個關鍵字不常常用了由於編譯器知道什麼變量該放什麼不應放,會自動優化。線程

相關文章
相關標籤/搜索