Memory Consistency Models
我們前面系列提及到,實際上程式在編譯與執行的時候,不一定會真的照你所寫的順序發生。而是可能改變順序、盡量最佳化,同時營造出彷彿一行一行執行下來的幻象,只要實際的結果和照順序 執行沒有差別就好。
這樣的幻象要成立,在於程式設計師和該系統(硬體、編譯器等產生、執行程式的平台)達成了一致的協定,系統保證程式設計師只要照著規則走,程式執行結果會是正確的。
但什樣叫做正確?正確的意思不是保證只會發生一種執行結果,而是定義在所有可能發生的執行結果中,哪些是允許的。我們把這樣的約定稱為Memory Consistency Models,系統要想辦法在保證正確的情況下,盡可能的最佳化,讓程式跑的又快又好。
Memory Consistency Models存在於許多不同的層次中,像是組合語言跑在硬體上時,因為處理器可以做指令重排和最佳化,雙方得確保執行結果和預期相同。或者,在將高階語言轉換成組語時,因為編譯器能夠將組合語言重排,雙方也得確保產生的結果和預期一致。換言之,從原始碼到最後實際執行的硬體上,大家都必須做好約定,才會跑出預期的結果。
最直覺的約定,Sequential Consistency
在1970年代,Lamport大大就在思考這個問題了。他提出一個如今最常見的Memory Consistency Model: Sequential Consistency,並且定義如下
A multiprocessor system is sequentially consistent if 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.
我們可以分成兩個觀點來看Sequential Consistency的定義, 1. 對於每個獨立的處理單元,執行時都維持程式的順序(Program Order) 2. 整個程式以某種順序在所有處理器上執行
Lamport的定義濃縮的很精煉,對於第一次看到的人會抓不太他想表達的重點,因為這實在是太蠢、太顯而易見了。第一點講你的程式在處理器內會照順序跑,第二個講所有處理器會以某種順序執行你的程式。你一定覺得,幹這不是廢話嗎XD
之所以會這樣覺得,是因為你一直以來都活在這樣的世界,就像活在牛頓時代以前的人,覺得拿手上的東西放開就會掉下來一樣自然。接下來我們會告訴你,想要保證這樣的現象,在現代的處理器上會限制很多最佳化的手段,讓程式執行的沒那麼快。如果你同意放棄一些約定,例如不保證每個處理單元維持程式執行的順序,我們還能榨出更多效能出來。
讓我再額外補充一點,Memory Consistency Model只是一個幻象的約定,程式執行的結果必須看起來是這樣,但是實際程式編譯完、跑在硬體上,想怎麼改變執行順序都可以,只要結果和約好的定義相同就好。
確保執行順序
我們將用這張圖來闡述Sequential Consistency的兩個要點。上圖左邊是Dekker's Alogrithm,一個關於critical section的演算法。如果我們確保Sequential Consistency,在每個處理器核心內維持program order,那麼這個程式就能確保同一時間只有一個處理器進入critical section。因為你一定是先立Flag,再檢查對方Flag是否立起,如果沒有才進入Critical Section。
但想像另一個情況,同一個處理器他可能直覺的認為Flag1, Flag2兩個變數沒有相依性,因此就算違反SC調換執行順序也沒差。如果P1和P2都先執行第二行,才執行第一行,那麼就會發生同時進入critical section的窘境。