1. 程式人生 > >並行程式設計——併發級別

並行程式設計——併發級別

轉自:http://www.cnblogs.com/jiayy/p/3246167.html

在看多核程式設計相關論文時,往往一個併發演算法會說自己是wait-free的或者lock-free的,或者是 non-blocking 的,這些專有詞彙其實表示的是併發的程度,或者說併發的級別。併發級別的理解是閱讀各種併發演算法設計論文以及併發資料結構實現的必備基礎。

1.1  Wait-freedom 無等待併發

Wait-freedom 指的是每一個執行緒都一直執行下去而無須等待外部條件,整個流程中任何操作都能在一個有限的步驟內完成,這是最高的併發級別,沒有任何阻塞。

 結合之前原子操作部分的知識,可以簡單認為能夠直接呼叫一個原子操作實現的演算法或程式就屬於Wait-free,比如下面的 increment_reference_counter 函式就是wait-free的,它封裝了atomic_increment這個原子自增原語,多個執行緒可以同時呼叫這個函式對同一個記憶體變數進行自增,而無須任何阻塞(其實也是有阻塞的,是匯流排鎖級別)

 與此做對比,CAS類的呼叫就不是wait-free的,注意wait-free的原語都不能包含內部迴圈,CAS原語使用時通常包含在“迴圈直到成功”的迴圈內部。

 void increment_reference_counter(rc_base* obj)

{

    atomic_increment(obj->rc);

}

1.2  Lock-freedom 無鎖併發

Lock-freedom 指的是整個系統作為一個整體一直執行下去,系統內部單個執行緒某段時間內可能會飢餓,這是比wait-freedom弱的併發級別,但系統整體上看依然是沒有阻塞的。所有wait-free的演算法顯然都滿足lock-free的要求。

 Lock-free演算法通常可以通過同步原語 CAS實現。

 void stack_push(stack* s, node* n)

{

    node* head;

    do

    {

        head = s->head;

        n->next = head;

    }

    while ( ! atomic_compare_exchange(s->head, head, n));

}

多個執行緒同時呼叫上述函式,理論上某個執行緒可以一直困在迴圈內部,但一旦有一個執行緒原子操作失敗而返回迴圈,意味著有其他執行緒成功執行了原子操作而退出迴圈,從而保證系統整體是沒有阻塞的。

 其實前面的原子自增函式也可以用下面的原語實現,在這種實現裡,不再是所有執行緒都無阻塞了,某些執行緒可能會因為CAS失敗而回繞若干次迴圈。

void increment_reference_counter(rc_base* obj)

{

       Int rc;

       Do {

       rc = obj->rc;

} while(!atomic_compare_exchange(obj->rc,rc,rc+1));

}

1.3  Obstruction-freedom 無阻塞併發

Obstruction-free 是指在任何時間點,一個孤立執行執行緒的每一個操作可以在有限步之內結束。只要沒有競爭,執行緒就可以持續執行,一旦共享資料被修改,Obstruction-free 要求中止已經完成的部分操作,並進行回滾,obstruction-free 是併發級別更低的非阻塞併發,該演算法在不出現衝突性操作的情況下提供單執行緒式的執行進度保證,所有 Lock-Free 的演算法都是 Obstruction-free 的。

1.4  Blocking algoithms 阻塞併發

阻塞類的演算法是併發級別最低的同步演算法,它一般需要產生阻塞。可以簡單認為基於鎖的實現是blocking的演算法。詳細參考第五章

上述幾種併發級別可以使用下圖描述:
藍色是阻塞的演算法,綠色是非阻塞演算法,金字塔越上方,併發級別越高,效能越好,右邊的金字塔是實現工具(原子操作、鎖、互斥體等)