C語言中 volatile 一文搞懂
簡單來說就兩個作用:
1. 保證不被編譯器優(yōu)化
? ?例如重復(fù)的賦值
? ?```
? ?volatile int value = 10;
? ?value = 10;
? ?value = 10;
? ?```
? ?volatile修飾后,一是這幾個語句都會得到執(zhí)行,二是順序不會改變
2. 保證可見性
? ?這里可見性的意思是,在多線程的環(huán)境下,當一個線程對一個變量改變,另一個線程能夠知道當前的值已經(jīng)改變,即:可見性的變量,在cpu改變他的值后,會立即寫入內(nèi)存中,而不是停留在cpu的cach中(基本cpu讀寫變量不是直接讀寫,而是緩存在cach中,有時cpu運算數(shù)據(jù)會直接讀寫到cach上,不能夠及時寫入內(nèi)存)。
? ?可見,**雖然volatile能夠保證可見性,但是不能保證操作的原子性**,原因如下:
? ?原子操作要求不能打斷整個操作流程,但volatile修飾的變量可以在其他線程被改變。要保證原子性需要添加相關(guān)機制如:自旋鎖。
鏈接:
1. 內(nèi)核中為什么不應(yīng)該使用volatile關(guān)鍵字
? ?```
? ?https://lp007819.wordpress.com/2013/01/20/%E5%86%85%E6%A0%B8%E4%B8%AD%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%BA%94%E8%AF%A5%E4%BD%BF%E7%94%A8volatile%E5%85%B3%E9%94%AE%E5%AD%97/
? ?```
2. chat_gpt問答:
? ?```
? ?為什么定義了volatile還是不能保證原子操作
? ?ChatGPT
? ?定義了 volatile 只能保證對變量的讀寫操作是可見的,并且編譯器不會對訪問該變量的指令進行優(yōu)化,但它不能保證原子操作。原子操作是指在多線程環(huán)境下,一個操作要么完全執(zhí)行成功,要么完全不執(zhí)行,沒有中間狀態(tài),不會被其他線程打斷。
? ?
? ?雖然 volatile 告訴編譯器不要優(yōu)化對該變量的訪問,但在多線程環(huán)境中,仍然可能發(fā)生并發(fā)問題。例如,如果多個線程同時對同一個 volatile 變量進行自增操作,由于沒有加鎖或其他同步機制,可能會出現(xiàn)競爭條件,導(dǎo)致結(jié)果不是預(yù)期的。這時候,volatile 不能保證原子性,因為多個線程之間可能會同時讀取、修改和寫回變量,而不考慮其他線程的操作。
? ?
? ?要實現(xiàn)原子操作,需要使用其他同步機制,比如使用互斥鎖(mutex)、原子操作庫或并發(fā)容器。這些機制可以確保在多線程環(huán)境下,某個特定代碼塊或操作只能被一個線程執(zhí)行,從而保證原子性和線程安全性。
? ?
? ?總結(jié):volatile 只能保證可見性和禁止編譯器優(yōu)化,但不能保證原子操作。要實現(xiàn)原子操作和線程安全性,需要使用其他同步機制來確保在多線程環(huán)境中操作的原子性。
? ?
? ?
? ?
? ?
? ?User
? ?這里的讀寫可見性是是什么意思
? ?ChatGPT
? ?在多線程編程中,可見性是指一個線程對共享變量的修改能夠被其他線程及時看到的特性。當一個線程修改了某個共享變量的值,其他線程在之后訪問該變量時能夠看到最新的值,而不是之前緩存的舊值。
? ?
? ?可見性問題主要涉及到多線程之間的內(nèi)存可見性?,F(xiàn)代計算機體系結(jié)構(gòu)中,每個線程都有自己的緩存(CPU cache),這些緩存用于加快對內(nèi)存的訪問速度。當一個線程對共享變量進行修改時,它首先會將修改后的值存儲在自己的緩存中,并且在合適的時機將這個修改刷新到主內(nèi)存中。其他線程在訪問這個共享變量時,可能會直接從自己的緩存中讀取值,而不是從主內(nèi)存中讀取。這就可能導(dǎo)致多個線程之間看到的是不一致的值,即出現(xiàn)了內(nèi)存可見性問題。
? ?
? ?為了解決內(nèi)存可見性問題,可以使用同步機制,如互斥鎖(mutex)或原子操作,來確保對共享變量的讀寫是原子的,從而保證修改的可見性。當一個線程獲取了鎖或執(zhí)行了原子操作時,其他線程必須等待,直到這個操作完成,從而保證了對共享變量的讀寫操作對其他線程是可見的。
? ?
? ?volatile 關(guān)鍵字也提供了可見性的保證。當一個變量被聲明為 volatile 時,對該變量的寫操作會立即刷新到主內(nèi)存,而對該變量的讀操作會從主內(nèi)存中獲取最新的值。這樣可以保證多線程之間對該變量的修改對其他線程是可見的。
? ?
? ?總結(jié):可見性是指多線程之間對共享變量修改的可見性。為了保證可見性,需要使用同步機制或 volatile 關(guān)鍵字來確保對共享變量的讀寫操作是原子的,并及時刷新到主內(nèi)存,從而保證其他線程能夠看到最新的值。
? ?
? ?
? ?
? ?
? ?User
? ?在這里,既然已經(jīng)保證可見性了,那為什么還不能保證是原子操作
? ?ChatGPT
? ?您是正確的,我之前的回答有一點混淆。在多線程編程中,volatile 關(guān)鍵字主要用于保證可見性,但它并不能保證原子操作。
? ?
? ?當一個變量被聲明為 volatile 后,對該變量的寫操作會立即刷新到主內(nèi)存,而對該變量的讀操作會從主內(nèi)存中獲取最新的值,確保了多個線程之間對變量值的可見性。這意味著當一個線程修改了 volatile 變量的值,其他線程可以立即看到最新的值,而不是過期的緩存值。
? ?
? ?然而,volatile 關(guān)鍵字并不能保證原子操作。原子操作是指一個操作要么完全執(zhí)行成功,要么完全不執(zhí)行,沒有中間狀態(tài)。在多線程環(huán)境中,多個線程同時對同一個變量進行讀寫操作時,仍然可能出現(xiàn)競爭條件和數(shù)據(jù)不一致的問題。即使對一個 volatile 變量進行自增或自減操作,在高并發(fā)情況下,多個線程同時讀取并修改該變量,可能導(dǎo)致結(jié)果不是預(yù)期的。
? ?
? ?要實現(xiàn)原子操作,需要使用其他同步機制,比如使用互斥鎖(mutex)、原子操作庫或并發(fā)容器。這些機制可以保證在多線程環(huán)境下,某個特定代碼塊或操作只能被一個線程執(zhí)行,從而保證了原子性和線程安全性。
? ?
? ?因此,volatile 關(guān)鍵字在多線程編程中主要用于保證對變量的可見性,而不是用于實現(xiàn)原子操作。要實現(xiàn)原子操作,需要使用其他同步手段來確保操作的原子性。
? ?```
? ?
? ?
? ?
? ?**轉(zhuǎn)載請附本文鏈接**