2014-11-14 60 views
0

我有這樣的班級組成。類聲明一個本身具有內部字典對象的對象的字典。如何使調用內部集合線程安全?

public class ValueObject 
    { 
     public float value = 0; 
    } 

    public class ValueDictionaryObject 
    { 
     private Dictionary<int, ValueObject> innerDict; 

     public float GetTotalValue() 
     { 
      lock (((ICollection)this.innerDict).SyncRoot) 
      { 
       float total = 0f; 
       foreach (var p in innerDict) 
        total += p.Value.value; 
       return total; 
      } 
     } 
    } 

    public class OuterDictionaryObject 
    { 
     private Dictionary<int, ValueDictionaryObject> outerDict; 

     public float GetTotalValueForSomeKey(int key) 
     { 
      lock (((ICollection)this.outerDict).SyncRoot) 
      { 
       return outerDict[key].GetTotalValue(); 
      } 
     } 
    } 


    var outer = new OuterDictionaryObject(); 

我有問題,當調用多個線程,似乎發生死鎖

float result = outer.GetTotalValueForSomeKey(key); 

如何做這個調用線程安全嗎?

+0

您有時會鎖定內部字典,有時鎖定在外部字典上。 「GetTotalValue」和「GetTotalValueForSomeKey」都是公共的,這取決於你嘗試調用它們的順序,鎖可能會以不同的順序被採用,並且會導致死鎖。 你想做什麼?這似乎是一個非常複雜的設置。 – xxbbcc 2014-11-14 20:10:46

+0

我需要一個線程安全的方式來從內部字典中獲取值的總和 – 2014-11-14 20:17:12

+1

這些字典是否在需要總和時被修改?如果是,則應該使用'ConcurrentDictionary'。 – xxbbcc 2014-11-14 20:19:01

回答

0

從您發佈的代碼中不清楚爲什麼會出現死鎖。是的,你有嵌套鎖獲取,這是死鎖的先決條件。但是在這裏沒有任何東西可以向我們展示如何在某些情景下顛倒鎖定購買順序,與我們在這裏看到的順序相反。

還是......

你應該儘量避免調用任何東西儘可能同時持有鎖定。有時這是不可避免的(例如,訪問您正在同步訪問的集合的成員,這意味着您必須調用該集合的成員)。但是,只有在你解決問題時必不可少的時候,你才應該打電話。

在這裏,好像你本來可以很容易地編寫這樣的代碼:

public class OuterDictionaryObject 
{ 
    private Dictionary<int, ValueDictionaryObject> outerDict; 

    public float GetTotalValueForSomeKey(int key) 
    { 
     ValueDictionaryObject vdo; 

     lock (((ICollection)this.outerDict).SyncRoot) 
     { 
      vdo = outerDict[key]; 
     } 

     return vdo.GetTotalValue(); 
    } 
} 

使用ConcurrentDictionary會產生類似的效果,因爲你不會被調用GetTotalValue()方法,直到同步訪問到字典對象已經完成。所以恕我直言,這將是一個很好的選擇。