[英]Is it threadsafe to add to a ConcurrentDictionary using foo[bar] = baz?
I'm not a fan of the methods attached to the ConcurrentDictionary
.我不喜欢附加到
ConcurrentDictionary
的方法。 AddOrUpdate
requires a func and GetOrAdd
adds when you are just looking for the key to get the value. AddOrUpdate
需要一个函数,当您只是在寻找获取值的键时,会添加GetOrAdd
。 So I want to use it like a normal dictionary (I'm using ContainsKey
to be safe)所以我想像普通字典一样使用它(我使用
ContainsKey
是安全的)
The docs say "To store a key/value pair in the dictionary unconditionally, and overwrite the value of a key that already exists", use The indexer's setter: dictionary[key] = newValue
. 文档说“要无条件地将键/值对存储在字典中,并覆盖已经存在的键的值”,请使用索引器的设置器:
dictionary[key] = newValue
。
But is this operation still threadsafe?但是这个操作仍然是线程安全的吗? The comments at the bottom say "All public and protected members of ConcurrentDictionary are thread-safe and may be used concurrently from multiple threads."
底部的评论说“ConcurrentDictionary 的所有公共和受保护成员都是线程安全的,可以从多个线程同时使用。” But I'm not 100% sure that they consider the above setter to be included here.
但我不是 100% 确定他们认为上面的 setter 包含在此处。
You can check the indexer
implementation of ConcurrentDictionary
at reference source -- https://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentDictionary.cs您可以在参考源检查
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);
}
}
If you notice the setter calls TryAddInternal
which is thread safe implementation如果您注意到 setter 调用
TryAddInternal
这是线程安全的实现
It is thread-safe in the sense that the internal state of the ConcurrentDictionary
will not be corrupted.在
ConcurrentDictionary
的内部 state 不会被破坏的意义上,它是线程安全的。 This is the main guarantee offered by this class.这是此 class 提供的主要保证。 So if you call
foo[bar] = fiz
from one thread and foo[bar] = biz
from another thread concurrently, then either fiz
or biz
will be finally stored as a value of the key bar
, provided that this key already existed in the collection (otherwise an exception will be thrown by both threads).因此,如果您同时从一个线程调用
foo[bar] = fiz
并同时从另一个线程调用 foo[bar foo[bar] = biz
,那么fiz
或biz
最终将存储为键bar
的值,前提是该键已经存在于集合(否则两个线程都会抛出异常)。
It's as if foo[bar]
was a variable with a size of a native integer or smaller, for example short count;
就好像
foo[bar]
是一个大小为原生 integer 或更小的变量,例如short count;
. . It is safe to update this variable from multiple threads, in the sense that its internal bits will not be partially updated, and will always hold the last value assigned.
从多个线程更新此变量是安全的,因为它的内部位不会被部分更新,并且将始终保存最后分配的值。 If this guarantee is not enough for your program, if for example you want the
count
to hold something meaningful, like how many times has been updated, then you'll have to synchronize the access to this variable.如果这个保证对你的程序来说还不够,例如你想让
count
保持有意义的东西,比如更新了多少次,那么你必须同步对这个变量的访问。
In the case of ConcurrentDictionary
, if you want the foo[bar]
to hold the value biz
only if it was previously fiz
, then this is not thread-safe: if (foo[bar] == fiz) foo[bar] = biz
.在
ConcurrentDictionary
的情况下,如果您希望foo[bar]
仅在之前为fiz
时才保留值biz
,那么这不是线程安全的: if (foo[bar] == fiz) foo[bar] = biz
. You'll have to use the TryUpdate
method: foo.TryUpdate(bar, biz, fiz)
.您必须使用
TryUpdate
方法: foo.TryUpdate(bar, biz, fiz)
。 Another case: if you want the foo[bar]
to hold the value biz
only if it was not previously fiz
, then you are out of luck.另一种情况:如果您希望
foo[bar]
仅在以前不是fiz
的情况下才保留值biz
,那么您就不走运了。 The ConcurrentDictionary
does not include a method that offers this guarantee. ConcurrentDictionary
不包括提供此保证的方法。 So you'll be forced to go back in using a Dictionary
+ manual synchronization.因此,您将被迫使用
Dictionary
+手动同步返回 go 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.