如何调用内部集合线程安全?

时间:2014-11-14 20:06:40

标签: c# multithreading dictionary collections thread-safety

我有这样的课堂作文。类声明一个对象的字典,这些对象本身具有内部字典对象。

    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);

如何使这个调用线程安全?

1 个答案:

答案 0 :(得分: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()方法。所以恕我直言,这也是一个不错的选择。