c# – .Net中的Dictionary可能会在并行阅读和写入时造成死锁吗?

前端之家收集整理的这篇文章主要介绍了c# – .Net中的Dictionary可能会在并行阅读和写入时造成死锁吗?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在和TPL一起玩,并尝试通过并行阅读和写作到同一个字典,找出我能做出多大的麻烦.

所以我有这个代码

private static void HowCouldARegularDicionaryDeadLock()
    {
        for (var i = 0; i < 20000; i++)
        {
            TryToReproduceProblem();
        }
    }

    private static void TryToReproduceProblem()
    {
        try
        {
            var dictionary = new Dictionary<int,int>();
            Enumerable.Range(0,1000000)
                .ToList()
                .AsParallel()
                .ForAll(n =>
                {
                    if (!dictionary.ContainsKey(n))
                    {
                        dictionary[n] = n; //write
                    }
                    var readValue = dictionary[n]; //read
                });
        }
        catch (AggregateException e)
        {
            e.Flatten()
                .InnerExceptions.ToList()
                .ForEach(i => Console.WriteLine(i.Message));
        }
    }

这真的很混乱,有很多异常抛出,主要是关键不存在,有几个关于索引的数组的界限.

但运行该应用程序一段时间后,它挂起,cpu百分比保持在25%,机器有8个内核.
所以我假设有2个线程以满容量运行.

然后我点了点跟踪,得到这个:

它匹配我的猜测,两个线程运行在100%.

两者都运行Dictionary的FindEntry方法.

然后我再次运行应用程序,用dottrace,这个时候结果略有不同:

这一次,一个线程正在运行FindEntry,另一个插入.

我的第一个直觉是它被锁死了,但后来我以为这不可能,只有一个共享资源,而且它没有被锁定.

那么应该如何解释呢?

ps:我不是想解决这个问题,它可以通过使用ConcurrentDictionary或者并行聚合来修复.我只是在寻找一个合理的解释.

解决方法

看起来像一个竞争条件(不是一个僵局) – 正如你所说,这导致内部混乱的状态.

字典不是线程安全的,因此从单独的线程(即使只有少数几个)并发读取和写入同一容器是不安全的.

一旦比赛条件受到打击,将会发生什么变化,在这种情况下,似乎是某种无限循环.

通常,一旦需要写入访问,就需要某种形式的同步.

猜你在找的C#相关文章