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