目前的計算機系統中,都是shared memory結構,提供統一的控制接口給軟件,編程
shared memory結構中,爲了memory correctness,能夠將問題分爲:memory consistency,和memory coherency。緩存
爲了memory consistency的正確性,是須要program的編寫者的操做,主要描述對一塊memory的不一樣的load,store之間的順序。多線程
而memory coherency,則對software是徹底透明的,主要爲了多cache在系統中的表現像單cache同樣。架構
memory consistency實現以後,coherency必定是保證的,可是coherency保證以後,consistency不必定能夠保證。併發
爲了不memory consistency,須要保證對同一address的,多個core或者多個線程store/load都是 in-ordered,爲不一樣的address,無所謂的。app
發生memory consistency,多是store-store,load-load,load-store。store-load之間的out-of order。性能
memory consistency model是一個系統性的問題,會直接影響程序(多線程,多進程)編寫。fetch
涉及到,processor的設計,memory system的設計,interconnect的設計,優化
compiler的優化,programming language的使用。atom
關於consistency model最簡單的描述是,讀操做須要返回最新寫入memory的值。
memory reorder只有在軟件實現lock-free 編程的時候,纔可能影響運算結果。
memory ordering模型,是併發程序設計的基礎。主要的內容:
1) atomic VS reorder
與cpu bus總線對齊的read/write,都是atomic的,若是非對齊,好比32bit的bus總線,訪問64bit的數據,
映射到str,ldr會變爲兩條指令,在單核多線程和多核的運行環境下,可能會出現half-read,half-write的
狀況。
RMW,read-modified-write,都是非atomic的。
爲此不少的微處理器,提出了atomic的指令,一條指令實現較複雜的功能,從而實現atomic性;
CMPXCHG(compare-and-exchange),XCHG等。這些atomic指令,只能保證單核多線程的原子性,在多核狀況下,仍是須要加lock;
reorder,的主要考慮是performance,在BP失敗或者cache miss的時候,都須要reorder,主要是STR或者LDR指令的亂序。
reorder的原則是硬件隱藏細節,使得數據的load,store,按single thread的順序正確執行。
reorder的類型包括,
Compiler Reordering,程序編譯期間,
Barrier指令保證先後的語句不會被reorder。
compiler memory barrier instruction:GNU編譯器,asm volatile("":::"memory")
__asm__ __volatile(""::::"memory")
intel ecc compiler
__memory_barrier()
Microsoft Visual C++
——ReadWriteBarrier()
CPU並感知不到compiler memory barrier的存在,並且實現compiler的memory barrier以後,
reorder仍是可能在CPU memory reorder中發生的。
CPU memory Ordering,程序執行期間:memory reorder,特指processor經過load,store指令,
system bus訪問system memory期間的亂序。
memory reorder的類型能夠分爲四類:
LoadLoad,
LoadStore,
StoreLoad,
StoreStore,
CPU memory order的實現,對軟件來講,是透明的。
CPU會進行reorder的緣由 ,多是指令的BP失敗,cache miss等,先將load,store放在load buffer,store buffer,invalid buffer中。
2) Memory Barrier
cpu的memory barrier,相比較於compiler來講,是一條真正的指令,針對四種memory reorder,目前有四種memory barrier的類型:
LoadLoad Barrier
LoadStore Barrier
StoreLoad Barrier
StoreStore Barrier
具體的barrier指令有三種:
Store Barrier(Write Barrier),Store Barrier先後的store操做,必須是按順序執行的,對load沒有影響。
Load Barrier(Read Barrier),Load Barrier先後的load操做,必須是按順序執行的,對write沒有影響。
Full Barrier(Load+Store Barrier),Full Barrier兩邊的任何操做,均不能夠交換順序。
CPU的memory model根據processor,tool chain的不一樣,有不少的選擇。
主要的CPU memory models:
Programming Order------------------Strong Memory Model
Sequential Consistency(SC模型)
Strict Consistency
Data Dependency Order------------Weaker Memory Model
強弱內存模型的主要區別點:但一個CPU核執行一連串的寫操做時,其餘的CPU核看到這些值的改變順序是否與其順序一致。
目前很難找到一個在硬件層面保證SC模型,因此當用上語言編程時,SC爲成爲一個重要的軟件內存模型,
Java5以後,用violation聲明共享變量,
C++11中,使用默認的順序約束memory_order_seq_cst,作原子操做,
使用這些技術以後,編譯器會限制編譯亂序,而且插入特定CPU的memory barrier指令,來保證原子操做。
最具典型的consistency model被稱爲SC (sequential consistency)。
sequential model在實現中的architecture:
1)系統中不帶cache的SC model,若是是多核,須要本身實現一個switch:
2)系統中帶有cache:多核狀況下,cache coherence protocol充當了switch的角色,能夠看作一個黑盒:
總結:
load-load、store-store,是必須按program order來的。
load-store、store-load,是必須按program order來的。
sequential consistency必須保證:1)program order,processor必須保證前一memory訪問結束,才能開始新的memory訪問;
在cache的系統中,必須保證全部的cache都被invalid或者update,收到相應的ack信號。
2)write atomicity,對同一地址的寫操做,必須是serialized,一樣必須是收到invalid和update的ack信號。
這些要求,針對任何load-store對。
SC Ordering Rule總結,表示的是單核的要求,RMW表示原子操做。
在硬件優化與SC模型中會出現的問題:
1) 沒有cache的狀況下,
1.帶write buffer的結構,read bypass的操做下,後邊的讀操做可能會越過寫操做。
2.重疊寫,overlapping write,多個不一樣地址的同時寫,後邊的寫操做,較前邊的寫操做,先完成。
3.非阻塞讀,nonblocking reads,多個不一樣地址的同時讀,後邊的讀操做,較前邊的讀操做,先完成。
2) 有cache的狀況下,
1.必須實現cache coherency協議。
2.檢查寫的ack信號。一個core必須等到另外一個core的寫ack信號以後,再發送下一個寫操做。
3.保證write atomicity,cache的本質是將一個值的改變,傳播給多個處理器的緩存,自己是非原子性的,因此有兩個要求;
1.針對同一地址的寫操做被串行化(serialized)
2.對一個新寫的值的讀操做,必須是全部其餘的core,都返回ack的狀況。
與特定的硬件優化結合起來的時候,SC模型的保證是有代價的。
其餘的memory model,較SC,有兩方面的改變:
1) 放鬆對程序次序的要求,只適用於不一樣地址的load,store操做;
2) 放鬆對原子性的要求,一些模型容許讀操做在「一個寫操做未對全部處理器可見的狀況下」執行。只適用於有buffer的體系結構。
X86多使用的是一種稱爲TSO(Total Store Order)的memory consistency model, 與SC model相比較。放開了store-load的順序要求。
只是放開了程序次序中的這一小部分。
TSO中,每一個processor都加入了一個write buffer,因此能夠memory order上來看store比load晚,可是指令上仍然是load先執行的。
相似於cache中的write-back的policy。
TSO model的實現:
若是programmer要求,store-load必須按順序執行,則須要在store以後,加入fence命令。
fence命令只能擋住本processor的執行,對其餘的processor起不到做用。
可是原子操做能夠,用exclusive的訪問,其餘的processor訪問不到該數據。
TSO Ordering Rules要求,針對單核的狀況:
Relaxed memory models:
relaxed model既有對program order方面的優化也有write atomicity方面的優化。
ARM和PowerPC,多使用relax model,一個example model,XC model,
XC model的ordering Rule,單核狀況:
XCmodel的實現:
程序設計時的memory相關的指令:
1) violatile,變量修飾詞,表示cpu不會每次都從cache中拿值,而是每次都必須訪問main-memory。通常計算機中的外設相關的變量都
須要設定爲violatile,防止被compiler優化。可是並不能用於構建原子操做。
2) 原子操做,分爲blocking和non-blocking兩種,相似於AXI中的lock trans和exclusive trans。
3) 互斥鎖,mutex,在多進程,多線程間使用,拿不到mutex時,進程或線程被休眠。blocking
底層使用lock transaction。
4) 自旋鎖(spinlock),在等待共有資源有效的過程當中,會一直等待,線程、進程不會被休眠。non-blocking
5) semaphore,等待必定數量的共有資源,直接在程序中聲明。blocking
底層使用lock transaction。
6) read-modify-write,使用strex或者ldrex彙編指令,對讀改寫進行包裝。non-blocking
7) compare-and-swap,等同於LL(load-link)、SC(store-conditional)指令,底層也是調用strex和ldrex指令,non-blocking
8) 其餘的atomic operation,test-and-set,fetch-and-add,compare-and-swap指令。
在exclusive trans設計中,會有兩個monitor,一個local monitor(只是monitor該cpu,通常放在cpu core內),
一個global monitor(monitor整個sys,通常放在主的interconnect中)
bus trans的memory type若是是Non-Shareable的,此時的exclusive只檢查local monitor,而後可能會直接返回Exok
若是是Shareable的,此時的exclusive,會檢查local monitor和global monitor,若是有violation,會直接返回Exok。
在有cache的系統中,而且此時的memory type是cacheable的,exclusive的訪問須要和local minitor,global monitor,SCU共同決定sync的結果。
這些model在實現中,都是依託於指令集來實現的,arm和intel都有提供相應的原子操做指令。
在程序代碼編寫的時候,也能夠本身控制,經過memory fence命令,來保證多核多線程對共享變量的訪問。
在單核系統中,也會出現memory consistent的問題,由於目前的cpu都是超標量,多線程,亂序執行的,因此program order並不能
反映到executed order。
之上是單核memory reorder的問題,以後寫一些多核數據一致性的問題。
軟件中數據的同步問題,
1.在單核多線程的狀況下,能夠經過disable全部中斷,包括cpu內核調度,來達到目的,只在sync var被處理以後,再放開中斷。
這樣能夠達到sync的目的,可是在增長了interrupt的latency。
2.在多核多線程的狀況下,須要保證多核之間的同步,arm增長了本身的指令,來鎖住bus,v6架構以前是swp指令,v6架構以後是ldrex指令。
下邊討論一下指令加鎖的應用:
X86的不少指令,均可以在前邊加lock,來保證原子性,加lock的指令,會保證對當前訪問的內存的互斥性。
在單核處理器系統中,可以在單條指令中完成的操做均可以被認爲是原子操做。由於中斷和線程切換都只能在指令與指令之間;
可是在多核處理器中,因爲多個core同時獨立的運行,即便能單條指令就能夠完成的操做,也會受到其餘core的干擾,
致使memory consistent出現問題,因此須要多核之間的同步。
X86的lock指令,作的即是多核之間訪問同一memory的同步,相似的有arm中的strex和ldrex,
arm中的strex和ldrex,是armv6以後才引進來的,以前使用的是swp,swpb指令,等效於lock bus+memory swap。
缺點有兩點:
1.可是直接鎖死bus會致使,其餘的core不能訪問bus,性能受到影響,
2.因爲這個指令既有str又有ldr,多以執行時間會比較長,若是這時有中斷,就必須等待這條指令執行結束,這樣增長了中斷的latency。
因此不管是多核仍是單核,swp指令都沒有目前的ldrex和strex方便。
參考文檔,Shared Memory Consistency Models A Tutorial.pdf
a primer on memory consistency and coherence.pdf
Weak vs. Strong Memory Models 網頁
淺談Memory Reordering 網頁
CPU cache and Memory Ordering 併發程序設計入門
https://www.kernel.org/doc/Documentation/memory-barriers.txt