内存屏障,先看这篇文章
剛看到這個(gè)詞的時(shí)候,我以為是白內(nèi)障,然后查了很多資料,才理解內(nèi)存屏障是干嘛的,我就不像很多其他文章說(shuō)得那么多了,我希望我說(shuō)得簡(jiǎn)單一些,讓大家看了我的文章都知道這個(gè)是怎么回事。
說(shuō)到內(nèi)存屏障,我們先從CPU性能優(yōu)化說(shuō)起
性能優(yōu)化的方法一,緩存
CPU的速度很快,到底有多快?我們就用光速來(lái)比喻CPU的執(zhí)行速度吧,反正就是執(zhí)行讀寫很快,但是CPU速度很快,內(nèi)存的速度很慢,怎么辦?
這時(shí)候,高速緩存出現(xiàn)了「先不抬杠說(shuō)寄存器哈」。比如有一個(gè)變量a ,CPU在很長(zhǎng)一段時(shí)間內(nèi)都需要使用它,如果把他放在內(nèi)存里面的話,每次讀寫的速度都很慢,這樣嚴(yán)重拖慢了CPU的執(zhí)行速度。
所以就出現(xiàn)了 緩存
緩存也是分類的,緩存分成了三類,我簡(jiǎn)單說(shuō)明下
緩存同步協(xié)議MESI如果在4個(gè)CPU在各自的L1 里面都有一個(gè)變量 i ,他們要把這個(gè)變量i寫入到內(nèi)存里面去,是以哪一個(gè)為準(zhǔn)呢?
這個(gè)時(shí)候就需要緩存的同步協(xié)議,每個(gè)cpu對(duì)緩存里面的變量操作的時(shí)候,要通知其他CPU,讓他們知道當(dāng)前的狀態(tài)。
CPU不僅需要發(fā)消息給其他CPU告訴他們狀態(tài),同時(shí)也要接收其他CPU發(fā)出來(lái)的狀態(tài)。
這樣做的最終目的,就是為了保證CPU對(duì)變量操作的一致性。
CPU性能優(yōu)化的方法二,運(yùn)行時(shí)指令重排
指令重排是個(gè)有意思的事情,如果把CPU當(dāng)成是一個(gè)人的話,他也是有自己的意識(shí)的,存在意識(shí)的東西,就會(huì)存在自己做事情的方法,比如,我今天要去打籃球,還要去幫媽媽打醬油,我是先打籃球還是先打醬油,因?yàn)閭€(gè)人的意識(shí)不同,做事情的先后順序也存在差異。
為什么出現(xiàn)指令重排?如果有一個(gè)CPU,我們假設(shè)是CPU0吧,它在寫緩存的的某個(gè)區(qū)塊的時(shí)候,發(fā)現(xiàn)這個(gè)緩存位置剛好被CPU1正常操作,那他怎么辦?有兩種方法,一種是等待CPU1執(zhí)行結(jié)束后自己再執(zhí)行,還有一種方法就是先去干其他的事情,很明顯,CPU為了提高自己的性能,它會(huì)選擇第二種方法,就是先去干其他的事情,干其他的事情,就出現(xiàn)上面描述的情況,指令重排了。
所以我們會(huì)有一個(gè)疑問(wèn)?代碼是按照程序員的想法去執(zhí)行的呢?還是按照CPU的想法去執(zhí)行的呢?回答當(dāng)然是需要按照程序員的意識(shí)去執(zhí)行的。
所以要求,指令重排遵循as-if-serial語(yǔ)義這個(gè)是什么意思呢?就是說(shuō)指令重排的結(jié)果不能影響程序員預(yù)期的結(jié)果,比如上面的代碼,重排后就會(huì)出現(xiàn)問(wèn)題,那么CPU就不能對(duì)指令進(jìn)行重排。
注意,上面所說(shuō)的as-if-serial語(yǔ)義針對(duì)的是單核CPU來(lái)說(shuō)
但是如果是下面的代碼
a = 100; b = c;上面兩條語(yǔ)句不存在依賴關(guān)系,它們可以進(jìn)行指令重排,因?yàn)橹嘏藕蟛粫?huì)影響最后的執(zhí)行結(jié)果。
高速緩存和指令重排序(reordings)存在的問(wèn)題
緩存機(jī)制和指令重排都是為了CPU運(yùn)算的性能優(yōu)化。會(huì)出現(xiàn)兩個(gè)問(wèn)題。1、緩存和內(nèi)存的數(shù)據(jù)并不是時(shí)實(shí)同步的,同一個(gè)內(nèi)存地址,不同的CPU看到的內(nèi)存值是不一樣的。因?yàn)镃PU運(yùn)行速度很快,假設(shè),CPU0 讀 地址 0x2345 的時(shí)候值為 1,這個(gè)時(shí)候,CPU1向 0x2345寫入了 2,CPU2再讀這個(gè)內(nèi)存 0x2345 的值的時(shí)候,發(fā)現(xiàn)它變成2了。所以就有問(wèn)題了。
出現(xiàn)的問(wèn)題是同一個(gè)時(shí)間點(diǎn)上,不同的CPU看到的同一個(gè)內(nèi)存地址數(shù)據(jù)不一樣
2、我們指令重排說(shuō)的as-if-serial語(yǔ)義只是針對(duì)單個(gè)CPU,那多個(gè)CPU呢?會(huì)出現(xiàn)什么問(wèn)題
看下面的例子:
看上面圖片
CPU0 要執(zhí)行兩條指令,CPU1也要執(zhí)行兩條指令,但是如果他們執(zhí)行的先后順序不同,那么x和y的結(jié)果也將存在差異。
第一種情況如下圖執(zhí)行順序會(huì)導(dǎo)致 x = 0 , y = 1。
第二種情況如下圖執(zhí)行順序會(huì)導(dǎo)致 x =1,y = 0。第三種情況如下圖執(zhí)行順序會(huì)導(dǎo)致 x = 1,y=1。
結(jié)果跟程序員的預(yù)期不符合 出現(xiàn)的問(wèn)題是,多個(gè)CPU,也就是我們經(jīng)常所說(shuō)的SMP系統(tǒng)下,會(huì)出現(xiàn)結(jié)果和預(yù)期不一致的問(wèn)題
最后說(shuō)內(nèi)存屏障(Memory Barrier)
內(nèi)存屏障就是用來(lái)解決上面兩個(gè)問(wèn)題的。這個(gè)是CPU廠商來(lái)搞定的。
寫內(nèi)存屏障(Store Memory Barrier) 寫內(nèi)存屏障的意思就是在寫內(nèi)存的后面加入指令 Store Barrier ,如果CPU有讀的也有寫的,加了這條指令,就保證先執(zhí)行寫入而不去做指令重排,這種顯示調(diào)用可以讓其他線程看到。其他線程會(huì)等這個(gè)執(zhí)行結(jié)束后再去操作,既然是等待,那也是降低性能的,好吧,降低性能也是沒(méi)有辦法的事情了。
就拿上面的 圖片來(lái)說(shuō)明A = 1 B = 1 這兩個(gè)是寫操作,我們加上寫內(nèi)存屏障,即使其他CPU有讀的指令,我們需要等待這個(gè)寫完成后,再進(jìn)行讀操作。
讀內(nèi)存屏障 (Load Memory Barrier) 在讀指令之前插入Load Barrier,可以讓高速緩存中的數(shù)據(jù)失效,強(qiáng)制從內(nèi)存加載最新的數(shù)據(jù),讓CPU緩存和主內(nèi)存保持一致,避免了緩存導(dǎo)致的一致性問(wèn)題。
總結(jié)
CPU為了性能,發(fā)明了緩存和指令重排,但是又因?yàn)榫彺婧椭噶钪嘏懦霈F(xiàn)了新的問(wèn)題,因?yàn)樾碌膯?wèn)題出現(xiàn),聰明的人類又發(fā)明了內(nèi)存屏障,之所謂,兵來(lái)將擋水來(lái)土掩就是這個(gè)道理。
文章是整理了自己看到資料的很多見(jiàn)解,后續(xù)會(huì)發(fā)新的文章進(jìn)一步講解,當(dāng)然了,或者也會(huì)不發(fā),我就是一只漂亮的鴿子,我鴿呀鴿呀鴿,祝大家周末愉快。
掃碼或長(zhǎng)按關(guān)注
回復(fù)「?籃球的大肚子」進(jìn)入技術(shù)群聊
總結(jié)
以上是生活随笔為你收集整理的内存屏障,先看这篇文章的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【c++实现】模拟银行叫号系统
- 下一篇: 为什么计算机连不上无线网络,电脑连不上w