【问题标题】:How to make a call internal collections thread-safe?如何使调用内部集合线程安全?
【发布时间】:2014-11-14 20:06:39
【问题描述】:

我有这样的班级构成。类声明了一个对象字典,这些对象本身具有一个内部字典对象。

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

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

【问题讨论】:

  • 您有时锁定内部字典,有时锁定外部字典。 GetTotalValueGetTotalValueForSomeKey 都是公开的,因此根据您尝试调用它们的顺序,锁定可能会以不同的顺序获取,并且您会遇到死锁。你想做什么?这似乎是一个相当复杂的设置。
  • 我需要一种线程安全的方法来从内部字典中获取值的总和
  • 在您需要总和时是否正在修改这些字典?如果是,您应该改用ConcurrentDictionary
  • 我正在使用 .net 3.5 并且无法使用 .net 4 (
  • 也许使用 ReaderWriterLockSlim ?

标签: c# multithreading dictionary collections thread-safety


【解决方案1】:

从您发布的代码中不清楚为什么会出现死锁。是的,你有嵌套锁获取,这是死锁的先决条件。但是这里没有任何内容可以向我们展示您在某些情况下是如何颠倒锁定获取顺序的。

还是……

你应该尽量避免在持有锁时调用任何东西。有时这是不可避免的(例如,访问您正在同步访问的集合的成员,这意味着您必须调用该集合的成员)。但是,您应该只在对您要解决的问题至关重要时才拨打电话。

在这里,您似乎可以像这样轻松编写代码:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多