並行編程——內存模型之順序一致性


1  定義

Sequential consistency , 簡稱 SC,定義如下

… the result of any execution is the same as if the operations of all the processors were executed in some sequential order, and the operations of each individual processor appear in this sequence in the order specified by its program [lamport]

下面用一個小例子說明這個定義的意思:

假設我們有兩個線程(線程1和線程2)分別運行在兩個CPU上,有兩個初始值為0的全局共享變量x和y,兩個線程分別執行下面兩條指令:

初始條件: x = y = 0;

表 1.1  CC 示意圖

線程 1

線程 2

x = 1;

y=1;

r1 = y;

r2 = x;

 因為多線程程序是交錯執行的,所以程序可能有如下幾種執行順序:

 表 1.2  CC示意圖2

Execution 1

Execution 2

Execution 3

x = 1;

r1 = y;

y = 1;

r2 = x;

結果:r1==0 and r2 == 1

y = 1;

r2 = x;

x = 1;

r1 = y;

結果: r1 == 1 and r2 == 0

x = 1;

y = 1;

r1 = y;

r2 = x;

結果: r1 == 1 and r2 == 1

Execution 1

Execution 2

Execution 3

當然上面三種情況並沒包括所有可能的執行順序,但是它們已經包括所有可能出現的結果了,所以我們只舉上面三個例子。我們注意到這個程序只可能出現上面三種結果,但是不可能出現r1==0 and r2==0的情況。

SC其實就是規定了兩件事情:
1)每個線程內部的指令都是按照程序規定的順序(program order)執行的(單個線程的視角)
2)線程執行的交錯順序可以是任意的,但是所有線程所看見的整個程序的總體執行順序都是一樣的(整個程序的視角)

第一點很容易理解,就是說線程1里面的兩條語句一定在該線程中一定是x=1先執行,r1=y后執行。第二點就是說線程1和線程2所看見的整個程序的執行順序都是一樣的,舉例子就是假設線程1看見整個程序的執行順序是我們上面例子中的Execution 1,那么線程2看見的整個程序的執行順序也是Execution 1,不能是Execution 2或者Execution 3。

有一個更形象點的例子。伸出你的雙手,掌心面向你,兩個手分別代表兩個線程,從食指到小拇指的四根手指頭分別代表每個線程要依次執行的四條指令。SC的意思就是說:
(1)對每個手來說,它的四條指令的執行順序必須是從食指執行到小拇指
(2)你兩個手的八條指令(八根手指頭)可以在滿足(1)的條件下任意交錯執行(例如可以是左1,左2,右1,右2,右3,左3,左4,右4,也可以是左1,左2,左3,左4,右1,右2,右3,右4,也可以是右1,右2,右3,左1,左2,右4,左3,左4)

其實說簡單點,SC就是我們最容易理解的那個多線程程序執行順序的模型。CC 保證的是對一個地址訪問的一致性,SC保證的是對一系列地址訪問的一致性。

2  幾種順序約束

順序的內存一致性模型為我們提供了一種簡單的並且直觀的程序模型。但是,這種模型實際上阻止了硬件或者編譯器對程序代碼進行的大部分優化操作。為此,人們提出了很多松弛的(relaxed)內存順序模型,給予處理器權利對內存的操作進行適當的調整。例如Alpha處理器,PowerPC處理器以及我們現在使用的x86, x64系列的處理器等等。下面是一些內存順序模型

2.1  TSO (整體存儲定序)

  • 數據載入間的執行順序不可改變。
  • 數據存儲間的順序不可改變。
  • 數據存儲同相關的它之前的數據載入間的順序不可改變。
  • 數據載入同其相關的它之前的數據存儲的順序可以改變。
  • 向同一個地址存儲數據具有全局性的執行順序。
  • 原子操作按順序執行。
  • 這方面的例子包括x86 TSO26和SPARC TSO.

2.2  PSO (部分存儲定序)

  • 數據載入間的執行順序不可改變。
  • 數據存儲間的執行順序可以改變。
  • 數據載入同數據存儲間相對順序可以改變。
  • 向同一個地址存儲數據具有全局性的執行順序。
  • 原子操作同數據存儲間的順序可以改變。
  • 這方面的例子包括SPARC PSO.

2.3  RMO (寬松內存定序)

  • 數據載入間的順序可以改變。
  • 數據載入同數據存儲間的順序可以改變。
  • 數據存儲間的順序可以改變。
  • 向同一個地址存儲數據具有全局性的執行順序。
  • 原子操作同數據存儲和數據載入間的順序可以改變。
  • 這方面的例子包括Power27和ARM.7

圖 1  一些體系架構的內存順序標准

 

圖 2  強內存順序模型和弱內存順序模型一些例子,

最左邊的內存順序一致性約束越弱,右邊的約束是在左邊的基礎上加上更多的約束,X86/64 算是比較強的約束。

 

3  亂序執行和內存屏障

任何非嚴格滿足SC規定的內存順序模型都產生所謂亂序執行問題,從編程人員的代碼,到編譯器,到CPU運行,中間可能至少需要對代碼次序做三次調整,每一次調整都是為了最終執行的性能更高。如下圖

圖 3  編譯亂序和運行亂序

串行時代,編譯器和CPU對代碼所進行的亂序執行的優化對程序員都是封裝好了的,無痛的,所以程序員不需要關心這些代碼在執行時被亂序成什么樣子。在單核多線程時代,mutex , semaphore 等機制在實現的時候考慮了編譯和執行的亂序問題,可以保證關鍵代碼區不會被亂序執行。在多核多線程時代,大部分情況下跟單核多線程是類似的,通過鎖調用可以保證共享區執行的順序性。但某種情況下,比如自己編寫無鎖程序,則會被暴露到這個問題面前。

 下面通過一個例子解釋亂序執行和內存屏障這兩個概念。

[來源:http://preshing.com/20120625/memory-ordering-at-compile-time]

示例代碼:

int A, B;

void foo()

{

    A = B + 1;

    B = 0;

}

普通編譯選項:

$ gcc -S -masm=intel foo.c

$ cat foo.s

        ...

        mov     eax, DWORD PTR _B  (redo this at home...)

        add     eax, 1

        mov     DWORD PTR _A, eax

        mov     DWORD PTR _B, 0

加上 -o2 優化編譯選項,可以看到,B的賦值操作順序變了

$ gcc -O2 -S -masm=intel foo.c

$ cat foo.s

        ...

        mov     eax, DWORD PTR B

        mov     DWORD PTR B, 0

        add     eax, 1

        mov     DWORD PTR A, eax

        ...

上述情況在某些場景下導致的后果是不可接受的,比如下面這段偽代碼中,生產者線程執行於一個專門的處理器之上,它先生成一條消息,然后通過更新ready的值,向執行在另外一個處理器之上的消費者線程發送信號,由於亂序執行,這段代碼在目前大部分平台上執行是有問題的:

處理器有可能會在將數據存儲到message->value的動作執行完成之前和/或其它處理器能夠看到message->value的值之前,執行consume函數對消息進行接收或者執行將數據保存到ready的動作。

圖 4  亂序執行

回到之前的例子,加上一句內存屏障命令

int A, B;

 

void foo()

{

    A = B + 1;

    asm volatile("" ::: "memory");

    B = 0;

}

依然采用 o2 優化編譯選項,發現這次B的賦值操作順序沒有變化

$ gcc -O2 -S -masm=intel foo.c

$ cat foo.s

        ...

        mov     eax, DWORD PTR _B

        add     eax, 1

        mov     DWORD PTR _A, eax

        mov     DWORD PTR _B, 0

        ...

在內存順序一致性模型不夠強的多核平台上,例子2的正確實現應該是下面這種,需要加上兩個內存屏障語句。

圖5  內存屏障

X86 的內存屏障 #define barrier() __asm__ __volatile__("": : :"memory")

更多X86內存屏障請參考 : http://blog.csdn.net/cnctloveyu/article/details/5486339

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM