加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-15 06:48:47 所属栏目:百科 来源:网络整理
导读:我正在和TPL一起玩,并尝试通过并行阅读和写作到同一个字典,找出我能做出多大的麻烦. 所以我有这个代码: private static void HowCouldARegularDicionaryDeadLock() { for (var i = 0; i 20000; i++) { TryToReproduceProblem(); } } private static void Tr
我正在和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或者并行聚合来修复.我只是在寻找一个合理的解释.

解决方法

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

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

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

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读