为什么这个ConcurrentDictionary上的TryGetValue / TryUpdate会死锁?

时间:2015-02-05 12:16:01

标签: c# concurrency deadlock concurrentdictionary

当我运行IncrementModelClientReOrderCount时遇到死锁但运行IncrementModelClientReOrderCountLOCK时问题就消失了。

区别在于lock()语句。

我假设使用ConcurrentDictionary可以减少死锁的可能性。

我是否错误地使用了ConcurrentDictionary:

public ConcurrentDictionary<Connection, ModelClient> ModelClients = new ConcurrentDictionary<Connection, ModelClient>();



    public bool IncrementModelClientReOrderCount(Connection mc)
    {
            ModelClient curValue;
            while (ModelClients.TryGetValue(mc, out curValue))
            {
                ModelClient curValue2 = curValue.Clone() as ModelClient; 
                curValue2.reOrderCount++;
                curValue2.DSP.seen = false;
                if (ModelClients.TryUpdate(mc, curValue2, curValue))
                    return true;

            }
            return false; 
    }


    public bool IncrementModelClientReOrderCountLOCK(Connection mc)
    {
        lock (ModelClients)
        {

            ModelClient curValue;
            while (ModelClients.TryGetValue(mc, out curValue))
            {
                ModelClient curValue2 = curValue.Clone() as ModelClient; 
                curValue2.reOrderCount++;
                curValue2.DSP.seen = false;
                if (ModelClients.TryUpdate(mc, curValue2, curValue))
                    return true;
            }
            return false; 
        }

    }


public class ModelClient : ICloneable
    {
        public string Symbol;
        public int Amount;
        public double Price;

        public ModelClient(string Symbol, int Amount, double Price)
        {
            this.Symbol = Symbol;
            this.Amount = Amount;
            this.Price = Price;
        }

        public object Clone() { return this.MemberwiseClone(); }
    }

1 个答案:

答案 0 :(得分:0)

“线程安全”集合本身是线程安全的 - 而不是写入集合时不存在的所有其他代码。 ConncurrentDictionary也不是无锁的 - 这意味着 锁定,因此有可能阻止对其某些方法的调用。 (例如,两个线程相互依赖于前进进度,同时在ConcurrentDictionary上调用阻塞方法)

锁的本质是保护两段代码不会同时执行并可能破坏状态 - 这意味着代码中几乎总有不止一个地方使用lock因此您可以编写与这两个块的执行重叠的代码并导致死锁。

线程安全集合只意味着您可以从多个线程中使用它,它本身不会破坏自己的状态(您无法访问且无法保护自己的状态)。使用线程安全的集合不会自动使您的所有代码都是线程安全的,也不会使您不必理解潜在的死锁区域并使用您自己的线程安全原语来补偿它们。

你还没有提供足够的代码让任何人确切知道你是如何陷入死锁的(或者它实际上是一个活锁)。但是,TryUpdate可以阻止,如果另一个名为TryUpdate的线程具有相同的curValue,我希望TryUpdate将返回false并且您的代码将会再试一次(即潜在的实时锁定

当您通过TryGetValue获取值并使用TryUpdate更新值时,您似乎不变。这个不变量是您的代码所特有的,您需要保护它。 lock是一个好的开始;但在接受lock是最佳解决方案之前,您可能需要更好地理解它。