繁体   English   中英

使用 foo[bar] = baz 添加到 ConcurrentDictionary 是否线程安全?

[英]Is it threadsafe to add to a ConcurrentDictionary using foo[bar] = baz?

我不喜欢附加到ConcurrentDictionary的方法。 AddOrUpdate需要一个函数,当您只是在寻找获取值的键时,会添加GetOrAdd 所以我想像普通字典一样使用它(我使用ContainsKey是安全的)

文档说“要无条件地将键/值对存储在字典中,并覆盖已经存在的键的值”,请使用索引器的设置器: dictionary[key] = newValue

但是这个操作仍然是线程安全的吗? 底部的评论说“ConcurrentDictionary 的所有公共和受保护成员都是线程安全的,可以从多个线程同时使用。” 但我不是 100% 确定他们认为上面的 setter 包含在此处。

您可以在参考源检查ConcurrentDictionaryindexer实现 -- https://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentDictionary.cs

    public TValue this[TKey key]
    {
        get
        {
            TValue value;
            if (!TryGetValue(key, out value))
            {
                throw new KeyNotFoundException();
            }
            return value;
        }
        set
        {
            if (key == null) throw new ArgumentNullException("key");
            TValue dummy;
            TryAddInternal(key, value, true, true, out dummy);
        }
    }

如果您注意到 setter 调用TryAddInternal这是线程安全的实现

在此处输入图像描述

ConcurrentDictionary的内部 state 不会被破坏的意义上,它是线程安全的。 这是此 class 提供的主要保证。 因此,如果您同时从一个线程调用foo[bar] = fiz并同时从另一个线程调用 foo[bar foo[bar] = biz ,那么fizbiz最终将存储为键bar的值,前提是该键已经存在于集合(否则两个线程都会抛出异常)。

就好像foo[bar]是一个大小为原生 integer 或更小的变量,例如short count; . 从多个线程更新此变量是安全的,因为它的内部位不会被部分更新,并且将始终保存最后分配的值。 如果这个保证对你的程序来说还不够,例如你想让count保持有意义的东西,比如更新了多少次,那么你必须同步对这个变量的访问。

ConcurrentDictionary的情况下,如果您希望foo[bar]仅在之前为fiz时才保留值biz ,那么这不是线程安全的: if (foo[bar] == fiz) foo[bar] = biz . 您必须使用TryUpdate方法: foo.TryUpdate(bar, biz, fiz) 另一种情况:如果您希望foo[bar]仅在以前不是fiz的情况下才保留值biz ,那么您就不走运了。 ConcurrentDictionary不包括提供此保证的方法。 因此,您将被迫使用Dictionary +手动同步返回 go 。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM