內(nèi)存屏障的作用
保證數(shù)據(jù)的可見性
我們知道,內(nèi)存中的數(shù)據(jù)除了在內(nèi)存中的副本,還有可能在各個(gè)核的CPU中,當(dāng)某個(gè)核修改了對(duì)應(yīng)cache中的數(shù)據(jù)后,這時(shí)其它核中對(duì)應(yīng)內(nèi)存地址的數(shù)據(jù)還有主存中的數(shù)據(jù)就不是最新的了,其它核為了能夠讀取到最新的數(shù)據(jù),需要執(zhí)行memory barrier指令,把store buffer中的修改寫到主存中。防止指令之間的重排序
前面講到一條指令的執(zhí)行會(huì)分為幾個(gè)步驟,也就是pipeline,為了得到更高的性能,編譯器或者處理器有可能會(huì)改變指令的執(zhí)行順序,以此來(lái)提高指令執(zhí)行的并行度。不管是編譯器還是處理器的重排序,都要遵守as-if-serial語(yǔ)義。as-if-serial說(shuō)的是,不管怎么重排序,在單線程中執(zhí)行這些指令,其結(jié)果應(yīng)該是一樣的。在多線程的情況下,需要memory barrier來(lái)保證整體的順序,否則會(huì)出現(xiàn)意想不到的結(jié)果。
內(nèi)存屏障分類
不同的處理器架構(gòu)的memory barrier也不太一樣,以Intel x86為例,有三種memory barrier
- LoadBarriers
- StoreBarriers
- FullBarriers
LoadBarriers
對(duì)應(yīng)lfence
指令,強(qiáng)制所有在load屏障指令之后的指令,都在該load屏障指令執(zhí)行之后被執(zhí)行,并且一直等到load緩沖區(qū)被該CPU讀完才能執(zhí)行之后的load指令。這使得從其他CPU暴漏出來(lái)的程序狀態(tài)對(duì)該CPU可見。
StoreBarriers
對(duì)應(yīng)sfence
指令,強(qiáng)制所有在store屏障之前的store指令,都在該store屏障指令執(zhí)行之前被執(zhí)行,并把store緩沖區(qū)的數(shù)據(jù)都刷到CPU緩存。這會(huì)使得程序的狀態(tài)對(duì)其他CPU可見。
FullBarriers
對(duì)應(yīng)mfence指令,保證該屏障指令執(zhí)行完成之后,在下一條指令執(zhí)行之前,所有在緩沖區(qū)的數(shù)據(jù)都刷新到CPU緩存里面。