再說 lock-free 編程

作者: Angel Lucifer  來源: 博客園  發布時間: 2009-04-09 10:00  閱讀: 10605 次  推薦: 0   原文鏈接   [收藏]  
 
摘要:這篇文章闡述如何再使用lock-free 技術的時候,它的一些負面影響。
[1] 說明一下lock-free編程
[2] 在實例中講解lock-free技術的影響

  lock-free  編程實在讓人又愛又恨。博主以前曾經寫過幾篇關于 lock-free 編程的文章。比如關于無鎖編程并發數據結構:迷人的原子。如果想更加深入的了解和實踐 lock-free 編程,可以參考CLR 2.0 Memory Model并發數據結構:Stack。這篇文章并不打算繼續闡述如何使用 lock-free 技術,而是談一下它的負面影響。從而讓大家對 lock-free 有個更加全面的認識。

  說到 lock-free 編程,現實中經常使用 CAS 原語。CAS 是英文 Compare and Swap 的簡寫。在 Windows 和 .NET 平臺,由于歷史原因,它被寫做 Interlocked API。原子操作在 x86 架構 CPU 對應的匯編指令有 XCHG、CMPXCHG、INC 等,當然還得加上 LOCK 作為前綴(更多信息請看 并發數據結構:迷人的原子)。

  CAS 原語在輕度和中度爭用情況下確實可以大幅度提高程序性能。但凡事有利必有弊,CAS 原語極度扼殺了程序的可伸縮性(其他缺點請看關于無鎖編程)。各位看官可能覺得這種觀點有點偏激,但事實如此。請容博主細細道來:

  • CAS 的原子性完全取決于硬件實現。大多數 Intel 和 AMD 的 CPU 采用了一種叫做 MOSEI 緩存一致性協議來管理緩存。這種架構下,處理器緩存內 CAS 操作相對成本低廉。但一旦資源爭用,就會引起緩存失效和總線占用。緩存越失效,總線越被占用,完成 CAS 操作也越被延遲。緩存爭用是程序可伸縮性殺手。當然對于非 CAS 內存操作來說也是如此,但 CAS 情況更加槽糕。
  • CAS 操作要比普通內存操作花費更多 CPU 周期。這歸功于緩存分級的額外負擔、刷新寫緩沖區與穿越內存柵欄限制和需求以及編譯器對 CAS 操作優化的能力。
  • CAS 經常被用在優化并行操作上。這意味著 CAS 操作失敗將導致重新嘗試某些指令(典型的回滾操作)。即便沒有任何爭用,它也會做一些無用功。不論成功或失敗都會增加爭用的風險。

  大多數 CAS 操作發生在鎖進入和退出時。盡管鎖可由單一 CAS 操作構建,但 .NET CLR Monitor 類卻使用了兩個(一個在 Enter 方法,另一個在 Exit 方法)。lock-free 算法也經常使用 CAS 原語來代替使用鎖機制。但是由于內存重組,這樣的算法也常常需要顯式的柵欄,即便使用了 CAS 指令。鎖機制非常邪惡,但大多數合格的開發人員都知道讓鎖持有盡量少的時間。因此,雖然鎖機制讓人非常討厭,且影響性能。但相對于大量,頻繁的 CAS 操作而言,它卻并不影響程序的可伸縮性。

  舉個很簡單的例子,增加計數 100,000,000 次。要做到這樣,有幾種方式。如果僅運行在單核單處理器上,我們可以使用普通的內存操作:

static volatile int counter = 0;
static void BaselineCounter()
{
    for (int i = 0; i < Count; i++)
    {
        counter++;
    }
}

 

  很明顯,上述代碼示例不是線程安全的,但給計數器提供了一個很好的時間基準。下面我們使用 LOCK INC 來作為線程安全的第一種方式:

static volatile int counter = 0;
static void LockIncCounter()
{
    for (int i = 0; i < Count; i++)
    {
        Interlocked.Increment(ref counter);
    }
}

 

  現在代碼示例線程安全了。我們還可以采取另外一種方式來保證線程安全。如果需要執行一些驗證(比如內存溢出保護),我們通常會使用這種方式。就是使用 CMPXCHG(即 CAS):

static volatile int counter = 0;
static void CASCounter()
{
    for (int i = 0; i < Count; i++)
    {
        int oldValue;
        do
        {
            oldValue = counter;
        }
        while (Interlocked.CompareExchange(ref counter, oldValue + 1, oldValue) != oldValue);
    }
}

 

[第1頁][第2頁]
0
0
 
標簽:CLR
 
 

文章列表

全站熱搜
創作者介紹
創作者 大師兄 的頭像
大師兄

IT工程師數位筆記本

大師兄 發表在 痞客邦 留言(0) 人氣()