volatile的介绍
生活随笔
收集整理的這篇文章主要介紹了
volatile的介绍
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
volatile的介紹
來看這個代碼:
int fun(int& a)
{
? ??
int b = a;
? ?
?int c = a;
? ??
return a+b+c;
}
int main()
{
? ??
int a=1;
? ? //.........做一些和a無關的事
? ?
?return fun(a);
}
這個代碼是很好優化的,因為編譯器知道a的值是1,參考上下文,編譯器又能知道b和c的值也是1,
而且根本沒有人用到了a,b,c三個變量,也沒有任何人在修改a,b,c三個的值,所以編譯器可能就直接把這個函數優化成:int main() { return 3; }了.
這么優化有什么問題嗎? 單線程沒問題,但多線程就有問題了,如果是多線程,a的值雖然在當前上下文中不會被修改,但可能正在被其他線程修改啊.于是上面的優化
就不對了. 那么,volatile關鍵字在這里就可以幫助我們了,volatile關鍵字提醒編譯器:?a可能隨時被意外修改.意外的意思是雖然當前這段代碼里看起來a不會變,但可能別的地方正在修改a的值哦.所謂"別的地方",某些情況下指的就是其他線程了.
那么,如果把代碼修改如下:
int fun(volatile int& a)
{
? ?
?int b = a;
? ?
?int c = a;
? ?
?return a+b+c;
}
int main()
{
??
?volatile int a=1;
? ? //.........做一些和a無關的事
? ?
?return fun(a);
}
編譯器就不敢優化了:
int fun(volatile int& a)
{
? ?
?int b = a; //這里從內存讀一下a吧,誰知道a還等不等于1呢
?
? int c = a; //這里再從內存讀一下a吧,誰知道a還等不等于1呢
? ?
?return a+b+c; ?//這里也從內存讀一下a吧,誰知道a還等不等于1呢
}
int main()
{
? ??
volatile int a=1;?//.........做一些和a無關的事
? ?
?return fun(a); //完全不敢優化啊,鬼知道a變成多少了....
}
同理的,這段代碼:
//..........
int a=0;
//做一些和a無關的事
if(a==0) doSomething();
//..........編譯器會發現,a肯定等于0啊,那我還if個毛啊,直接優化掉!
//..........
int a=0;
//做一些和a無關的事
doSomething(); //if被去掉了
//..........
但,一旦添加了volatile,編譯器就不敢優化了.例如:
//..........
volatile int a=0;
//做一些和a無關的事
if(a==0) doSomething(); //可不敢優化這里! 誰知道a變成多少了!
//..........
這便是volatile的作用了.
必須補充說明,volatile和鎖沒有一毛錢的關系,該加鎖依然需要加鎖.給變量添加volatile并不會讓其自動擁有一個鎖.所以該加鎖還得加.
網上教程里經常見到雙檢鎖保證單例模式的代碼,簡化一下,大概邏輯如下:
static int* instance;
int& get_instance()
?{
? ? if( !instance ) { //檢查如果單例的指針是0
? ? ? ? 此處有某種鎖; //則在此處上鎖
if( !instance ) { ?//再判斷一次,以防等待鎖期間有別的線程已經new完了
? ? ?instance = new int; //確認無誤則new之
}
? ? }
? ? return *instance;
}
int main()
{
? ? int& i = get_instance();
? ? i = 111;
? ? return 1;
}
1.volatile的主要作用是:提示編譯器該對象的值有可能在編譯器未監測的情況下被改變。volatile類似于大家所熟知的const也是一個類型修飾符。volatile是給編譯器的指示來說明對它所修飾的對象不應該執行優化。volatile的作用就是用來進行多線程編程。在單線程中那就是只能起到限制編譯器優化的作用。
2.如果沒有volatile,你將無法在多線程中并行使用到基本變量。
3.如果一個基本變量被volatile修飾,編譯器將不會把它保存到寄存器中,而是每一次都去訪問內存中實際保存該變量的位置上。這一點就避免了沒有volatile修飾的變量在多線程的讀寫中所產生的由于編譯器優化所導致的災難性問題。所以多線程中必須要共享的基本變量一定要加上volatile修飾符。當然了,volatile還能讓你在編譯時期捕捉到非線程安全的代碼。
4.volatile對基本類型和對用戶自定義類型的使用與const有區別,比如你可以把基本類型的non-volatile賦值給volatile,但不能把用戶自定義類型的non-volatile賦值給volatile,而const都是可以的。還有一個區別就是編譯器自動合成的復制控制不適用于volatile對象,因為合成的復制控制成員接收const形參,而這些形參又是對類類型的const引用,但是不能將volatile對象傳遞給普通引用或const引用。
5.在編寫多線程程序中使用volatile的關鍵四點:
? ? ? 1).將所有的共享對象聲明為volatile;
? ? ? 2).不要將volatile直接作用于基本類型;
? ? ? 3).當定義了共享類的時候,用volatile成員函數來保證線程安全;
? ? ? 4).多多理解和使用volatile和LockingPtr!(強烈建議) 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀
來看這個代碼:
int fun(int& a)
{
? ??
int b = a;
? ?
?int c = a;
? ??
return a+b+c;
}
int main()
{
? ??
int a=1;
? ? //.........做一些和a無關的事
? ?
?return fun(a);
}
這個代碼是很好優化的,因為編譯器知道a的值是1,參考上下文,編譯器又能知道b和c的值也是1,
而且根本沒有人用到了a,b,c三個變量,也沒有任何人在修改a,b,c三個的值,所以編譯器可能就直接把這個函數優化成:int main() { return 3; }了.
這么優化有什么問題嗎? 單線程沒問題,但多線程就有問題了,如果是多線程,a的值雖然在當前上下文中不會被修改,但可能正在被其他線程修改啊.于是上面的優化
就不對了. 那么,volatile關鍵字在這里就可以幫助我們了,volatile關鍵字提醒編譯器:?a可能隨時被意外修改.意外的意思是雖然當前這段代碼里看起來a不會變,但可能別的地方正在修改a的值哦.所謂"別的地方",某些情況下指的就是其他線程了.
那么,如果把代碼修改如下:
int fun(volatile int& a)
{
? ?
?int b = a;
? ?
?int c = a;
? ?
?return a+b+c;
}
int main()
{
??
?volatile int a=1;
? ? //.........做一些和a無關的事
? ?
?return fun(a);
}
編譯器就不敢優化了:
int fun(volatile int& a)
{
? ?
?int b = a; //這里從內存讀一下a吧,誰知道a還等不等于1呢
?
? int c = a; //這里再從內存讀一下a吧,誰知道a還等不等于1呢
? ?
?return a+b+c; ?//這里也從內存讀一下a吧,誰知道a還等不等于1呢
}
int main()
{
? ??
volatile int a=1;?//.........做一些和a無關的事
? ?
?return fun(a); //完全不敢優化啊,鬼知道a變成多少了....
}
同理的,這段代碼:
//..........
int a=0;
//做一些和a無關的事
if(a==0) doSomething();
//..........編譯器會發現,a肯定等于0啊,那我還if個毛啊,直接優化掉!
//..........
int a=0;
//做一些和a無關的事
doSomething(); //if被去掉了
//..........
但,一旦添加了volatile,編譯器就不敢優化了.例如:
//..........
volatile int a=0;
//做一些和a無關的事
if(a==0) doSomething(); //可不敢優化這里! 誰知道a變成多少了!
//..........
這便是volatile的作用了.
必須補充說明,volatile和鎖沒有一毛錢的關系,該加鎖依然需要加鎖.給變量添加volatile并不會讓其自動擁有一個鎖.所以該加鎖還得加.
網上教程里經常見到雙檢鎖保證單例模式的代碼,簡化一下,大概邏輯如下:
static int* instance;
int& get_instance()
?{
? ? if( !instance ) { //檢查如果單例的指針是0
? ? ? ? 此處有某種鎖; //則在此處上鎖
if( !instance ) { ?//再判斷一次,以防等待鎖期間有別的線程已經new完了
? ? ?instance = new int; //確認無誤則new之
}
? ? }
? ? return *instance;
}
int main()
{
? ? int& i = get_instance();
? ? i = 111;
? ? return 1;
}
1.volatile的主要作用是:提示編譯器該對象的值有可能在編譯器未監測的情況下被改變。volatile類似于大家所熟知的const也是一個類型修飾符。volatile是給編譯器的指示來說明對它所修飾的對象不應該執行優化。volatile的作用就是用來進行多線程編程。在單線程中那就是只能起到限制編譯器優化的作用。
2.如果沒有volatile,你將無法在多線程中并行使用到基本變量。
3.如果一個基本變量被volatile修飾,編譯器將不會把它保存到寄存器中,而是每一次都去訪問內存中實際保存該變量的位置上。這一點就避免了沒有volatile修飾的變量在多線程的讀寫中所產生的由于編譯器優化所導致的災難性問題。所以多線程中必須要共享的基本變量一定要加上volatile修飾符。當然了,volatile還能讓你在編譯時期捕捉到非線程安全的代碼。
4.volatile對基本類型和對用戶自定義類型的使用與const有區別,比如你可以把基本類型的non-volatile賦值給volatile,但不能把用戶自定義類型的non-volatile賦值給volatile,而const都是可以的。還有一個區別就是編譯器自動合成的復制控制不適用于volatile對象,因為合成的復制控制成員接收const形參,而這些形參又是對類類型的const引用,但是不能將volatile對象傳遞給普通引用或const引用。
5.在編寫多線程程序中使用volatile的關鍵四點:
? ? ? 1).將所有的共享對象聲明為volatile;
? ? ? 2).不要將volatile直接作用于基本類型;
? ? ? 3).當定義了共享類的時候,用volatile成員函數來保證線程安全;
? ? ? 4).多多理解和使用volatile和LockingPtr!(強烈建議) 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀
總結
以上是生活随笔為你收集整理的volatile的介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计模式总结: 5种创建型,7种结构型,
- 下一篇: 位域(bit fields)简介