簡介: 多核多線程已經成爲當下一個時髦的話題,而無鎖編程更是這個時髦話題中的熱點話題。Linux 內核多是當今最大最複雜的並行程序之一,爲咱們分析多核多線程提供了絕佳的範例。內核設計者已經將最新的無鎖編程技術帶進了 2.6 系統內核中,本文以 2.6.10 版本爲基礎作相關解釋 。html
如何正確有效的保護共享數據是編寫並行程序必須面臨的一個難題,一般的手段就是同步。同步可分爲阻塞型同步(Blocking Synchronization)和非阻塞型同步( Non-blocking Synchronization)。 linux
阻塞型同步是指當一個線程到達臨界區時,因另一個線程已經持有訪問該共享數據的鎖,從而不能獲取鎖資源而阻塞,直到另一個線程釋放鎖。常見的同步原語有mutex、semaphore 等。若是同步方案採用不當,就會形成死鎖(deadlock),活鎖(livelock)和優先級反轉(priority inversion),以及效率低下等現象。 爲了下降風險程度和提升程序運行效率,業界提出了不採用鎖的同步方案,依照這種設計思路設計的算法稱爲非阻塞型算法,其本質特徵就是中止一個線程的執行不會阻礙系統中其餘執行實體的運行。 c++
當今比較流行的 Non-blocking Synchronization 實現方案有三種: 算法
1. Wait-free 數據庫
Wait-free 是指任意線程的任何操做均可以在有限步以內結束,而不用關心其它線程的執行速度。 Wait-free 是基於 per-thread 的,能夠認爲是 starvation-free 的。很是遺憾的是實際狀況並不是如此,採用 Wait-free 的程序並不能保證 starvation-free,同時內存消耗也隨線程數量而線性增加。目前只有極少數的非阻塞算法實現了這一點。 編程
2. Lock-free windows
Lock-Free 是指可以確保執行它的全部線程中至少有一個可以繼續往下執行。因爲每一個線程不是 starvation-free 的,即有些線程可能會被任意地延遲,然而在每一步都至少有一個線程可以往下執行,所以系統做爲一個總體是在持續執行的,能夠認爲是 system-wide 的。全部 Wait-free 的算法都是 Lock-Free 的。 多線程
3. Obstruction-free less
Obstruction-free 是指在任什麼時候間點,一個孤立運行線程的每個操做能夠在有限步以內結束。只要沒有競爭,線程就能夠持續運行。一旦共享數據被修改,Obstruction-free 要求停止已經完成的部分操做,並進行回滾。全部 Lock-Free 的算法都是 Obstruction-free 的。 ide
綜上所述,不可貴出 Obstruction-free 是 Non-blocking synchronization 中性能最差的,而 Wait-free 性能是最好的,但實現難度也是最大的,所以 Lock-free 算法開始被重視,並普遍運用於當今正在運行的程序中,好比linux內核。
通常採用原子級的 read-modify-write 原語來實現 Lock-Free 算法,其中 LL 和 SC 是 Lock-Free 理論研究領域的理想原語,但實現這些原語須要 CPU 指令的支持,很是遺憾的是目前沒有任何 CPU 直接實現了 SC 原語。根據此理論,業界在原子操做的基礎上提出了著名的 CAS(Compare - And - Swap)操做來實現 Lock-Free 算法,Intel 實現了一條相似該操做的指令:cmpxchg8。
CAS 原語負責將某處內存地址的值(1 個字節)與一個指望值進行比較,若是相等,則將該內存地址處的值替換爲新值,CAS 操做僞碼描述以下:
Bool CAS(T* addr, T expected, T newValue)
{
if( *addr == expected )
{
*addr = newValue;
return true;
}
else
return false;
}
在實際開發過程當中,利用 CAS 進行同步,代碼以下所示:
do{ 備份舊數據;
基於舊數據構造新數據;
}while(!CAS( 內存地址,備份的舊數據,新數據 ))
就是指當二者進行比較時,若是相等,則證實共享數據沒有被修改,替換成新值,而後繼續往下運行;若是不相等,說明共享數據已經被修改,放棄已經所作的操做,而後從新執行剛纔的操做。容易看出 CAS 操做是基於共享數據不會被修改的假設,採用了相似於數據庫的 commit-retry 的模式。當同步衝突出現的機會不多時,這種假設能帶來較大的性能提高。
加鎖的層級
根據複雜程度、加鎖粒度及運行速度,能夠得出以下圖所示的鎖層級:
其中標註爲紅色字體的方案爲 Blocking synchronization,黑色字體爲 Non-blocking
synchronization。Lock-based 和 Lockless-based 二者之間的區別僅僅是加鎖粒度的不一樣。圖中最底層的方案就是你們常用的mutex和 semaphore 等方案,代碼複雜度低,但運行效率也最低。
Michael and Scott的僞碼:
http://www.cs.rochester.edu/research/synchronization/pseudocode/queues.html
Michael &Scott 無鎖隊列c++實現(linux下測試經過):
http://www.cnblogs.com/napoleon_liu/archive/2010/08/07/1794566.html
Lock Free Queue implementation in C++ and C#(依賴windows平臺):
http://www.codeproject.com/Articles/23317/Lock-Free-Queue-implementation-in-C-and-C