您好,登錄后才能下訂單哦!
首先簡單介紹一下編譯器對代碼優化的概念:
編譯器優化:在不影響程序結果的情況下,改變程序的執行順序提高效率
優化級別有:
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){}
}
在flag前加上volatile,這時候不管怎么優化flag都是從內存中讀取的,一改變他就可以讀入新的值,因而這個程序當接收到2信號時就可以正常退出了。
volatile要經常使用在多線程中,因為編譯器對于多執行流的情況不太會判斷,所以volatile經常要使用在多線程來讓cpu用的變量都是新的。
與volatile相對的是register,即告訴編譯器把這個變量放到寄存器中。
但是這register個關鍵字不經常用了因為編譯器知道什么變量該放什么不該放,會自動優化。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。