參考文檔: [1] Multiprocessors should support simple memory consistency models [2] Shared Memory Consistency Models: A Tutorial 一、什么是內(nèi)存模型,?內(nèi)存模型 (memory model),,也叫內(nèi)存一致性模型 (memory consistency model),它可以簡單的理解為一系列對內(nèi)存讀寫操作的規(guī)定,,包括針對內(nèi)存讀寫操作的重排序規(guī)則,、可見性規(guī)則(一次讀操作能否看到最近一次寫入的結(jié)果?)等等,。根據(jù)內(nèi)存模型包含的一系列規(guī)定,,我們可以推斷出內(nèi)存操作的結(jié)果,例如:
看一個具體的例子,,對于下面的代碼,,初始時
根據(jù)內(nèi)存模型,我們可以推斷出最終打印出的是多少:
所以說,,內(nèi)存模型其實是一種抽象 (abstraction),。抽象這個概念在計算機領域內(nèi)應用可以說是極為廣泛了,抽象可以向我們屏蔽底層復雜的細節(jié),。例如,匯編語言對機器代碼進行了抽象,,使得我們不需要自己編寫 以硬件級別的內(nèi)存模型為例,它實際上是對底層硬件內(nèi)存系統(tǒng)的抽象,,有了內(nèi)存模型,,我們不需要了解底層的物理內(nèi)存、cache和處理器到底怎么工作的,,我們只需要參照內(nèi)存模型的規(guī)定,,就能知道兩個內(nèi)存操作指令會被會發(fā)生重排序,我這次讀內(nèi)存操作得到的值可能是多少,,等等,。
二,、內(nèi)存模型的分類
內(nèi)存模型可以分為軟件層面的內(nèi)存模型和硬件層面的內(nèi)存模型。正如第一小節(jié)介紹的那樣,,它們其實都是一系列對于內(nèi)存讀寫操作的規(guī)定,,根據(jù)它們可以推測內(nèi)存讀寫操作的結(jié)果。 1. 軟件層面的內(nèi)存模型軟件層面的內(nèi)存模型最為人熟知的應該就是 Java內(nèi)存模型(JMM) 了,。JMM本質(zhì)上是在硬件內(nèi)存模型之上又做了一層抽象,,使得Java程序員只需要了解JMM就可以編寫出正確的并發(fā)代碼,而無需過多了解硬件層面的內(nèi)存模型,。下面是JMM和硬件層面的存儲系統(tǒng)的對應:
2. 硬件層面的內(nèi)存模型硬件層面的內(nèi)存模型則是直接建立在硬件存儲系統(tǒng)(內(nèi)存、緩存,、寄存器) 上的抽象,。 系統(tǒng)軟件等一些底層的軟件會用到硬件層面的內(nèi)存模型,例如編譯器,、設備驅(qū)動,、操作系統(tǒng)等等。 舉個例子,,我們使用匯編語言進行編程就需要了解硬件層面的內(nèi)存模型,,因為匯編語言沒有提供軟件級別的內(nèi)存模型抽象。 3. 總結(jié)這兩種內(nèi)存模型的關系如下圖所示,,其中橫線表示內(nèi)存模型(或者說內(nèi)存模型提供的抽象):
三,、理解內(nèi)存模型帶來的影響
內(nèi)存模型這層抽象對它的上層和下層都有影響,對可移植性也有影響,。 以軟件層面的內(nèi)存模型JMM為例,,它不僅影響了Java程序的編寫者(JMM這層抽象之上),也會影響Java編譯器的設計者(JMM這層抽象之下),,編譯器設計者應該確保編譯器對指令的重排序等操作不會違反JMM規(guī)定,。 同樣,對于硬件層面的內(nèi)存模型,,它不僅對其上層的系統(tǒng)程序的編寫者有影響,,也會對其下層的硬件設計者有影響。同樣也會影響程序的可移植性,,例如把一個遵循強內(nèi)存模型機器上編寫的程序移植到一個弱內(nèi)存模型的機器上,,結(jié)果可能會出錯。 四,、常見的內(nèi)存模型本節(jié)將討論硬件層面的內(nèi)存模型,,對于軟件層面的內(nèi)存模型不做討論。 1. 順序一致性內(nèi)存模型 (Sequential Consistency, SC)順序一致性模型最初由Lamport針對多處理器系統(tǒng)定義:
對于定義中的operation究竟指的是何種操作,,Lamport沒給出定義,。如果將順序一致性的定義運用于內(nèi)存模型,則順序一致性的定義如下,,參考[2] “4. Understanding Sequential Consistency”: (1) 所有處理器核心對于內(nèi)存的讀寫操作的最終結(jié)果和某種按順序執(zhí)行的結(jié)果一樣 要實現(xiàn)(1),,就必須要求內(nèi)存操作看起來像是原子的 (atomically),參考[2] “4. Understanding Sequential Consistency”,。 上述順序一致性的定義中,,只要求最終結(jié)果和“按照xxx順序”執(zhí)行的一樣,并不是說處理器一定得“按照xxx順序”依次執(zhí)行指令,,只要最終結(jié)果一樣就符合順序一致性模型,。 結(jié)合上一小節(jié)來理解,對于SC模型之上的程序員來講,,他看到的內(nèi)存操作是順序一致的,,無須考慮硬件層面可能采取的優(yōu)化措施,他可以簡單地認為指令就是按照程序順序原子執(zhí)行的(可能硬件層面并非是這樣執(zhí)行),;但是對于SC模型之下的硬件設計者,,由于只要求最終結(jié)果一樣,因此可以采取適當?shù)膬?yōu)化措施,,例如指令重排序等等,,只要確保最終結(jié)果符合順序一致的標準即可。 額外補充一點,,順序一致性定義中 (1) 的 “按順序執(zhí)行”是什么意思呢,請看下面的圖:
順序一致性模型給程序員的視角順序一致性內(nèi)存模型呈現(xiàn)給程序員的抽象視圖如下: 如圖所示,內(nèi)存和處理器之間有一層內(nèi)存模型提供的抽象接口,,這層接口就像一個“多口開關”,,每次只能撥給一個處理器,原子的處理該處理器上的一個內(nèi)存操作,,可以按照任意的順序在各個處理器之間撥來撥去,;每個處理器按順序發(fā)射 (issue) 指令,。
順序一致性模型的優(yōu)缺點分析顯然,順序一致性模型的優(yōu)點就是對程序員很友好,,因為根據(jù)順序一致性,,程序員可以很容易的推測出自己程序的執(zhí)行結(jié)果。 但是,,順序一致性對于硬件設計者就不那么友好了,,它限制了store buffer等優(yōu)化措施的使用,從而限制了程序在硬件上執(zhí)行所能獲取的性能,。 因此,,為了獲取更高的程序執(zhí)行性能,現(xiàn)代計算機往往都不采用順序一致性內(nèi)存模型,,而是使用放松的內(nèi)存一致性模型 (Relaxed Memory Model),,這些模型相對于順序一致性模型的要求做了一些放松,對硬件設計者更加友好,,使得硬件設計者可以采取更多的優(yōu)化措施 (重排序,、store buffer等等),提升程序的執(zhí)行性能,;但是另一方面,,對于軟件程序員就不像順序一致性模型那么友好了,程序員推斷程序的執(zhí)行結(jié)果變得有點困難,,有時候還需要手動采用內(nèi)存屏障等策略來確保得到自己想要的結(jié)果,。 2. 放松的內(nèi)存一致性模型 (Relaxed Memory Model)閱讀本小節(jié)之前,需要對cache相關的知識有所了解,,包括緩存一致性,、store buffer、store bypassing (store forwarding) 等概念有所理解,,可以參考 Memory Barriers: a Hardware View for Software Hackers,。 所謂放松的一致性模型,正如上一小節(jié)所說,,就是對順序一致性模型中的某些條件進行了放松,。根據(jù)放松的條件不同,又有不同的分類。本文將介紹最常見的一種放松的內(nèi)存模型——允許發(fā)生StoreLoad重排序的內(nèi)存模型,。 這種放松的內(nèi)存模型允許StoreLoad重排序,,那么硬件設計者如何利用這個放松了的條件來獲取更快的執(zhí)行速度呢? 答案就是store buffer,。store buffer是一個先進先出的緩沖,,位于CPU核心和Cache之間,用于緩存內(nèi)存寫操作,。 在順序一致性模型中,,要求一個處理器上對變量的修改,能被其他處理器上后續(xù)的讀操作看到,。對于一個存在Cache和緩存一致性協(xié)議的計算機來說,,這就意味著一個處理器在寫變量之前,必須先在總線上發(fā)送通知,,通知其他處理器將自己對應的副本置為失效,,在收到其他處理器的完成置為失效操作的確認之后,該處理器才能執(zhí)行寫操作,。這一操作的開銷是比較大的,。 而在允許StoreLoad重排序的系統(tǒng)中,由于我們有store buffer,,所以可以把寫操作緩存在store buffer,,等到特定的時機再將store buffer多條內(nèi)容一并刷新到cache或主存,并通知其他處理器將副本置為失效,,從而整體上減少了內(nèi)存寫操作帶來的延遲,,提高了速度和性能。 硬件設計者是爽了,,提升了內(nèi)存操作的速度,但是這卻給軟件程序員帶來一個問題,,就是一個處理器上對變量的修改其他處理器上不是立即可見的,,因為。為了解決這個問題,,需要程序員顯式地加上內(nèi)存屏障等指令來保證可見性,。 既然其他處理器不能立馬看到當前處理器的修改,那么當前處理器能看到自己的修改嗎,?例如 這個問題的答案取決于具體的硬件實現(xiàn),不過在當前主流的處理器中,,都可以看到自己做出的修改,,正如上面的圖所示,處理器核心可以同時看到store buffer和cache中的內(nèi)容,,所以處理器核心是可以看到緩存在當前處理器store buffer中的寫操作的 (這一技術被叫做 store bypassing 或 store forwarding),。 允許StoreLoad重排序的常見內(nèi)存模型有:
這些內(nèi)存模型在具體實現(xiàn)上稍有不同,,例如處理器P1對變量x作出了修改,并緩存在store buffer中,,那么當處理器P1讀取x的新值的時候,,是不是也確保其他處理器也能看到新值。 這些內(nèi)存模型都有提供一個額外的特性——causality(參考 [1] ),。假設有4個處理器,, 放松的內(nèi)存模型總結(jié)主要介紹了允許StoreLoad重排序的內(nèi)存模型,,該模型用store buffer實現(xiàn),,可使用store bypassing來確保當前處理器可以看到自己的修改,具有causality特性,。 x86平臺采用的TSO模型就屬于該類模型,。 更多不同處理器支持的重排序可以參考 https://en./wiki/Memory_ordering 中的表格。 |
|