2010-12-14 31 views
6

何時應該使用鎖?只有在修改數據或訪問它時?僅在修改vs整個方法時鎖定

public class Test { 
    static Dictionary<string, object> someList = new Dictionary<string, object>(); 

    static object syncLock = new object(); 

    public static object GetValue(string name) { 
     if (someList.ContainsKey(name)) { 
      return someList[name]; 
     } else { 
      lock(syncLock) { 
       object someValue = GetValueFromSomeWhere(name); 
       someList.Add(name, someValue); 
      } 
     } 
    } 
} 

是否應該在整個塊周圍鎖定,或者只是將其添加到實際修改中?我的理解是,仍然會有一些競爭條件,一個呼叫可能沒有找到並開始添加,而另一個呼叫可能也遇到同樣的情況 - 但我不確定。鎖定仍然非常混亂。我還沒有遇到上述類似代碼的任何問題,但我可能只是幸運的。上面的任何幫助都將被appriciated以及任何好的資源如何/何時鎖定對象。

回答

8

您也必須在讀取時鎖定,否則您可能會獲得不可靠的數據,或者如果併發修改物理更改目標數據結構,則可能會發生異常。

在上面的例子中,您需要確保多個線程不會同時添加該值,因此在檢查它是否已經存在時至少需要一個讀鎖定。否則多個線程可能會決定添加,發現值不存在(因爲此檢查未鎖定),然後所有嘗試依次添加(獲取鎖後)

如果您有多個線程,則可以使用ReaderWriterLockSlim只讀和幾個寫道。在上面的代碼中,一旦您決定需要添加它,您將獲得讀鎖以執行檢查並升級到寫鎖。在大多數情況下,只需要一個讀鎖(它允許讀者線程仍然並行運行)。

有一個可用的.Net 4鎖定原語here的摘要。在你深入到多線程代碼之前,你應該明白這一點。選擇正確的鎖定機制可以帶來巨大的性能差異。

到目前爲止,你是正確的,你是幸運的 - 這是併發錯誤的常見特徵。如果沒有有針對性的負載測試,他們往往很難複製,這意味着正確的設計(當然,徹底的測試)對於避免令人尷尬和混亂的生產錯誤至關重要。

+0

大鏈接,所有可用的鎖定機制。我只聽說過'lock'。 – MyNameIsJob 2010-12-14 17:35:06

+0

祝你好運 - 如果你能掌握這些東西,你將成爲少數幾個爲多核開發做好準備的開發人員。 – 2010-12-14 17:36:34

1

在檢查name的存在性之前鎖定整個塊。否則,在理論上,另一個線程可以在檢查和添加它的代碼之間添加它。

實際上,當你執行Add操作時,鎖定確實不會執行任何操作。所有這些都會阻止另一個線程同時添加一些內容。但是,由於其他線程已經決定要添加,所以只要釋放鎖,它就會嘗試去做。

+1

另一個過程?術語很重要。 – 2010-12-14 16:41:12

+0

真正的enuf。糾正。 – 2010-12-14 16:43:20

1

如果資源只能由多個線程訪問,則不需要任何鎖定。

如果一個資源可以被多個線程訪問並且可以被修改爲,那麼所有的訪問/修改都需要被同步。在您的示例中,如果GetValueFromSomeWhere需要很長時間才能返回,則可以使用name中的相同值進行第二次調用,但該值尚未存儲在Dictionary中。

0

ReaderWriterLock或超薄版本,如果你在4.0以下。

您將獲得讀取鎖定的讀取權限(將允許併發讀取),並在寫入內容時將鎖定升級到寫入鎖定(此時只允許寫入一次,並將阻止所有讀取直到完成,以及併發寫入線程)。

確保與圖案解除鎖定,以避免死鎖:

  void Write(object[] args) 
      { 


        this.ReaderWriterLock.AquireWriteLock(TimeOut.Infinite); 

        try 
        { 
         this.myData.Write(args); 

        } 
        catch(Exception ex) 
        { 

        } 
        finally 
        { 

         this.ReaderWriterLock.RelaseWriterLock(); 
        } 

      }