久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

內(nèi)存關(guān)卡/柵欄

 pphsy 2013-12-19
         原文出處: Martin Thompson   譯文出處: coderbee

在這篇文章里,,我將討論并發(fā)編程里最基礎(chǔ)的技術(shù)–以?xún)?nèi)存關(guān)卡或柵欄著稱(chēng),那讓進(jìn)程內(nèi)的內(nèi)存狀態(tài)對(duì)其他進(jìn)程可見(jiàn),。

CPU 使用了很多技術(shù)去嘗試和適應(yīng)這樣的事實(shí):CPU 執(zhí)行單元的性能已遠(yuǎn)遠(yuǎn)超出主內(nèi)存性能,。在我的“Writing Combining”文章,我只是談及其中一種技術(shù),。CPU 使用的用來(lái)隱藏內(nèi)存延遲的最普通技術(shù)是管線(xiàn)化指令,,然后付出巨大努力和資源去嘗試重排序這些管線(xiàn)來(lái)最小化緩存不命中的有關(guān)拖延。

當(dāng)一個(gè)程序執(zhí)行的時(shí)候,,它不在乎,,如果重排序后的指令提供了一樣的最終結(jié)果。例如,,在一個(gè)循環(huán)內(nèi),,如果循環(huán)內(nèi)沒(méi)有操作使用循環(huán)計(jì)算器,循環(huán)計(jì)數(shù)器什么時(shí)候更新是不在乎的,。編譯器和 CPU 自由地重排序指令來(lái)最大化地利用 CPU,,直到下一次迭代即將開(kāi)始時(shí)才更新它(循環(huán)計(jì)數(shù)器)。也可能,,在一個(gè)循環(huán)的執(zhí)行過(guò)程中,,這個(gè)變量可能存儲(chǔ)在一個(gè)寄存器里,永遠(yuǎn)不會(huì)推到緩存或主內(nèi)存,,因此,,它對(duì)其它 CPU 永遠(yuǎn)不可見(jiàn)。

CPU 核包含多個(gè)執(zhí)行單元,。例如,,一個(gè)現(xiàn)代的Intel CPU 包含6個(gè)執(zhí)行單元,可以做一組數(shù)學(xué),,條件邏輯和內(nèi)存操作的組合,。每個(gè)執(zhí)行單元可以做這些任務(wù)的組合,。這些執(zhí)行單元并行地操作,允許指令并行地執(zhí)行,。如果從其它 CPU 來(lái)觀察,,這引入了程序順序的另一層不確定性。

最終,,但緩存不命中發(fā)生時(shí),,現(xiàn)代 CPU 可以根據(jù)內(nèi)存加載的結(jié)果做一個(gè)假設(shè),然后基于這個(gè)假設(shè)繼續(xù)執(zhí)行直至實(shí)際數(shù)據(jù)的加載完成,。

提供“程序順序”保留了 CPU 和編譯器自由地做它們認(rèn)為可以提升性能的事情

cpu-memory-cache-system

加載(load)和存儲(chǔ)(store)到緩存和主內(nèi)存是被緩沖和重排序的,,使用加載(load),存儲(chǔ)(store),,和寫(xiě)組合(writing-combining)緩存,。這些緩存是關(guān)聯(lián)的隊(duì)列,允許快速查找,。這種查找是必須的,,當(dāng)一個(gè)稍后的加載需要讀取一個(gè)之前存儲(chǔ)的、還沒(méi)有到達(dá)緩存的值時(shí),。上圖描繪了現(xiàn)代多核 CPU 的簡(jiǎn)化視圖,。它顯示了執(zhí)行單元如何使用本地寄存器和緩存來(lái)管理內(nèi)存,與緩存子系統(tǒng)來(lái)回傳送,。

在多線(xiàn)程環(huán)境下,,需要采用一些技術(shù)來(lái)讓程序結(jié)果及時(shí)可見(jiàn)。我不會(huì)在這篇文章里涉及緩存一致性,。僅僅假設(shè)一旦內(nèi)存被推到緩存,,然后有一個(gè)協(xié)議消息將發(fā)生,以確保所有共享數(shù)據(jù)的緩存是一致的,。這種使內(nèi)存對(duì)處理器核可見(jiàn)的技術(shù)被稱(chēng)為內(nèi)存關(guān)卡或柵欄。

內(nèi)存關(guān)卡提供了兩種屬性,。首先,,它們保留了外部可見(jiàn)的程序順序,通過(guò)確保所有的,、關(guān)卡兩側(cè)的指令表現(xiàn)出正確的程序順序,,如果從其他CPU觀察。第二,,它們使內(nèi)存可見(jiàn),,通過(guò)確保數(shù)據(jù)傳播到緩存子系統(tǒng)。

內(nèi)存關(guān)卡是一個(gè)復(fù)雜的主題,。它們?cè)诓煌?CPU 架構(gòu)上的實(shí)現(xiàn)是非常不同的,。Intel CPU 有一個(gè)關(guān)聯(lián)的強(qiáng)內(nèi)存模型,。本篇將以 x86 CPU 為基礎(chǔ)講解。

 

存儲(chǔ)關(guān)卡(store barrier)

存儲(chǔ)關(guān)卡,,在x86 上是”sfence”指令,,強(qiáng)迫所有的、在關(guān)卡指令之前的 存儲(chǔ)指令在關(guān)卡以前發(fā)生,,并且讓 store buffers 刷新到發(fā)布這個(gè)指令的 CPU cache,。這將使程序狀態(tài)對(duì)其他 CPU 可見(jiàn),這樣,,如果需要它們可以對(duì)它做出響應(yīng),。一個(gè)實(shí)際的好例子是下面的、簡(jiǎn)化的,、來(lái)自Disruptor的類(lèi)BatchEventProcessor,。當(dāng)sequence被更新后,其他消費(fèi)者和生產(chǎn)者知道這個(gè)消費(fèi)者的進(jìn)展,,并進(jìn)行適當(dāng)?shù)捻憫?yīng),。所有在關(guān)卡之前對(duì)內(nèi)存的更新現(xiàn)在都可見(jiàn)了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private volatile long sequence = RingBuffer.INITIAL_CURSOR_VALUE;
// from inside the run() method
T event = null;
long nextSequence = sequence.get() + 1L;
while (running)
{
    try
    {
       //  譯注:barrier 會(huì)讀取其他sequence 的值,所以這里面有個(gè) load barrier 指令,。
        final long availableSequence = barrier.waitFor(nextSequence);
        while (nextSequence <= availableSequence)
        {
            event = ringBuffer.get(nextSequence);
            boolean endOfBatch = nextSequence == availableSequence;
            eventHandler.onEvent(event, nextSequence, endOfBatch);
            nextSequence++;
        }
        sequence.set(nextSequence - 1L);
        // store barrier 插入到這里 !!!
    }
    catch (final Exception ex)
    {
        exceptionHandler.handle(ex, nextSequence, event);
        sequence.set(nextSequence);
        // store barrier 插入到這里 !!!
        nextSequence++;
    }
}

加載關(guān)卡(load barrier)

加載關(guān)卡,,在x86 上是”lfence”指令,強(qiáng)迫所有的,、加載指令之后的指令在關(guān)卡之后發(fā)生,,然后等待那個(gè) CPU 的 load buffer 排空。這使其它 CPU 暴露出來(lái)的程序狀態(tài)對(duì)這個(gè) CPU 可見(jiàn),,在做出更多進(jìn)展之前,。這個(gè)的一個(gè)好例子是前面引用的 BatchEventProcessor 的 sequence 被其它生產(chǎn)者或消費(fèi)者讀取時(shí),Disruptor 里有等價(jià)的指令,。

 

Full Barrier

Full Barrier,,在x86 上是”mfence”指令,在 CPU 上是加載和存儲(chǔ)關(guān)卡的組合,。

 

Java 存儲(chǔ)模型(Java Memory Model)

Java 存儲(chǔ)模型里,,volatile 字段在寫(xiě)入后插入一個(gè)存儲(chǔ)關(guān)卡,在讀取前插入加載關(guān)卡,。類(lèi)里面修飾為 final 的字段在它們被初始化后插入一個(gè)存儲(chǔ)指令,,以確這些字段在構(gòu)造函數(shù)完成、有可用引用到這個(gè)對(duì)象時(shí)是可見(jiàn)的,。

 

原子指令和軟件鎖(Atomic Instructions and Software Locks)

原子指令,,如x86里的 “l(fā)ock …” 指令,是高效的 full barrier,,它們鎖住存儲(chǔ)子系統(tǒng)來(lái)執(zhí)行操作,,有受保證的全序關(guān)系(total order),,即使跨 CPU。軟件鎖通常使用存儲(chǔ)關(guān)卡,,或原子指令來(lái)達(dá)到可視性和保留程序順序,。

 

存儲(chǔ)關(guān)卡對(duì)性能的影響(Performance Impact of Memory Barriers)

存儲(chǔ)關(guān)卡阻止了 CPU 執(zhí)行很多隱藏內(nèi)存延遲的技術(shù),因此有它們有顯著的性能開(kāi)銷(xiāo),,必須考慮,。為了達(dá)到最大性能,最好對(duì)問(wèn)題建模,,這樣處理器可以做工作單元,,然后讓所有必須的存儲(chǔ)關(guān)卡在工作單元的邊界上發(fā)生。采用這種方法允許處理器不受限制地優(yōu)化工作單元,。把必須的存儲(chǔ)關(guān)卡分組是有益的,,那樣,在第一個(gè)之后的 buffer 刷新的開(kāi)銷(xiāo)會(huì)小點(diǎn),,因?yàn)闆](méi)有工作需要進(jìn)行重新填充它,。




    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多