原子操做 memory_order

https://zh.cppreference.com/w/cpp/atomic/memory_order程序員

std::atmoic和std::memory_order只有在多cpu多線程狀況下,無鎖編程纔會用到編程

編譯器優化而產生的指令亂序,cpu指令流水線也會產生指令亂序。固然這些亂序指令都是爲了同一個目的,優化執行效率。
happens-before:按照程序的代碼序執行,對同一線程,就是一個操做要在另外一個操做以前執行。對多個線程,某一個線程的操做A要在另外一線程的操做B以前發生。若順序變了,可能就不能達到咱們但願的效果。緩存

synchronized-with:不一樣線程間,對於同一個原子操做,須要同步關係,store()操做必定要先於 load(),也就是說 對於一個原子變量x,先寫x,而後讀x是一個同步的操做,讀x並不會讀取以前的值,而是當前寫x的值。多線程

int a=0,int b=1;
void func(){
    a=b+22;
    b=22;
}

func代碼沒有被編譯器優化,按照正常指令執行:
movl    b(%rip), %eax ; 將 b 讀入 %eax(通用寄存器)
addl    $22, %eax ; %eax 加 22, 即 b + 22
movl    %eax, a(%rip) ; % 將 %eax 寫回至 a, 即 a = b + 22
movl    $22, b(%rip) ; 設置 b = 22
優化後:
movl    b(%rip), %eax ; 將 b 讀入 %eax
movl    $22, b(%rip) ; b = 22
addl    $22, %eax ; %eax 加 22
movl    %eax, a(%rip) ; 將 b + 22 的值寫入 a,即 a = b + 2

 

6種memory_order 主要分紅3類,relaxed(鬆弛的內存序),sequential_consistency(內存一致序),acquire-release(獲取-釋放一致性)app

relaxed(鬆弛的內存序):沒有順序一致性的要求,也就是說同一個線程的原子操做仍是按照happens-before關係,但不一樣線程間的執行關係是任意。性能

sequential_consistency(內存一致序):這個是以犧牲優化效率,來保證指令的順序一致執行,至關於不打開編譯器優化指令,按照正常的指令序執行(happens-before),多線程各原子操做也會Synchronized-with,(譬如atomic::load()須要等待atomic::store()寫下元素才能讀取,同步過程),固然這裏還必須得保證一致性,讀操做須要在「一個寫操做對全部處理器可見」的時候才能讀,適用於基於緩存的體系結構優化

acquire-release(獲取-釋放一致性):這個是對relaxed的增強,relax序因爲沒法限制多線程間的排序,因此引入synchronized-with,但並不必定意味着,統一的操做順序。ui

內存屏障Memory Barrier

程序在運行時內存實際的訪問順序和程序代碼編寫的訪問順序不必定一致,這就是內存亂序訪問。內存亂序訪問行爲出現的理由是爲了提高程序運行時的性能。內存亂序訪問主要發生在兩個階段:atom

  1. 編譯時,編譯器優化致使內存亂序訪問(指令重排)
  2. 運行時,多 CPU 間交互引發內存亂序訪問

Memory Barrier 可以讓 CPU 或編譯器在內存訪問上有序。一個 Memory Barrier 以前的內存訪問操做一定先於其以後的完成。Memory Barrier 包括兩類:spa

  1. 編譯器Memory Barrier
  2. CPU Memory Barrier

內存屏障阻礙了CPU採用優化技術來下降內存操做延遲,必須考慮所以帶來的性能損失.

volatile   /ˈvɒlətaɪl/

用來修飾變量,一般用於創建語言級別的 memory barrier。

易變性:在彙編層面反映出來,就是兩條語句,下一條語句不會直接使用上一條語句對應的volatile變量的寄存器內容,而是從新從內存中讀取。

不可優化性:volatile告訴編譯器,不要對我這個變量進行各類激進的優化,甚至將變量直接消除,保證程序員寫在代碼中的指令,必定會被執行。

順序性:多線程中,C/C++ Volatile變量與非Volatile變量之間的操做,是可能被編譯器交換順序的。

相關文章
相關標籤/搜索