![](/img/trans.png)
[英]Function under test “foo” calls external function “bar(baz)” multiple times => How can return value of “baz” be modified specifically for each call?
[英]Is it threadsafe to add to a ConcurrentDictionary using foo[bar] = baz?
我不喜欢附加到ConcurrentDictionary
的方法。 AddOrUpdate
需要一个函数,当您只是在寻找获取值的键时,会添加GetOrAdd
。 所以我想像普通字典一样使用它(我使用ContainsKey
是安全的)
文档说“要无条件地将键/值对存储在字典中,并覆盖已经存在的键的值”,请使用索引器的设置器: dictionary[key] = newValue
。
但是这个操作仍然是线程安全的吗? 底部的评论说“ConcurrentDictionary 的所有公共和受保护成员都是线程安全的,可以从多个线程同时使用。” 但我不是 100% 确定他们认为上面的 setter 包含在此处。
您可以在参考源检查ConcurrentDictionary
的indexer
实现 -- 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
,那么fiz
或biz
最终将存储为键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.