2014-11-14 29 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()方法,直到同步访问到字典对象已经完成。所以恕我直言,这将是一个很好的选择。