[英]Is this using of dictionary thread-safe or not?
Here is two my variants of method, which returns a string, associated with enum value (kept in dictionary).这是我的两个方法变体,它返回一个字符串,与枚举值相关联(保存在字典中)。 First variant is slower, but thread-safe, second is faster, but i don't know, whether it is thread-safe or not.
第一个变体较慢,但线程安全,第二个变体更快,但我不知道它是否是线程安全的。 First:
第一的:
string GetStringForEnum (SomeEnum e)
{
string str = null;
lock (someDictionary) //someDictionary is not used anywhere else (only in this method)
{ if (!someDictionary (e, out str)) { someDictionary.Add (e, "somehowCreatedString"); }
return str;
}
Second variant:第二种变体:
string GetStringForEnum (SomeEnum e)
{
string str = null;
if (!someDictionary (e, out str))
{
lock (someDictionary) //someDictionary is not used anywhere else (only in this method)
{ if (!someDictionary (e, out str)) { someDictionary.Add (e, "somehowCreatedString"); }
}
return str;
}
Second variant is not used "lock" each time, but is it thread-safe or not?第二种变体不是每次都使用“锁”,但它是否是线程安全的?
There are 2 problems here:这里有两个问题:
lock (someDictionary)
- this is dis-advised, even if the dictionary is not used elsewhere. lock (someDictionary)
- 这是不建议的,即使字典没有在其他地方使用。 It is a theoretical argument but the (future) code of the Dictionary class could lock on itself.这是一个理论上的争论,但字典 class 的(未来)代码可能会锁定自己。
if (,someDictionary (e, out str))
without a lock. if (,someDictionary (e, out str))
没有锁。 I assume this is a call to TryGetValue()
.我假设这是对
TryGetValue()
的调用。 This simply is not thread-safe, your Read could be interrupted by a Write in another thread.这根本不是线程安全的,您的读取可能会被另一个线程中的写入中断。 This could end in all sorts of errors (index out of range, null reference).
这可能会以各种错误结束(索引超出范围,null 参考)。 The errors will be very rare (= hard to reproduce).
错误将非常罕见(= 难以重现)。
The documentation on Dictionary
has a section on thread safety: Dictionary
上的文档有一个关于线程安全的部分:
A
Dictionary(Of TKey, TValue)
can support multiple readers concurrently, as long as the collection is not modified .只要集合未被修改
Dictionary(Of TKey, TValue)
就可以同时支持多个读者。 Even so, enumerating through a collection is intrinsically not a thread-safe procedure.即便如此,通过集合进行枚举本质上不是线程安全的过程。 In the rare case where an enumeration contends with write accesses, the collection must be locked during the entire enumeration.
在枚举与写访问争用的极少数情况下,必须在整个枚举期间锁定集合。 To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.
要允许多个线程访问集合以进行读写,您必须实现自己的同步。
For a thread-safe alternative, see
ConcurrentDictionary(Of TKey, TValue)
.有关线程安全的替代方法,请参阅
ConcurrentDictionary(Of TKey, TValue)
。
So:所以:
TryGetValue
is safe to use from multiple threads because it is read-only. TryGetValue
是只读的,因此可以安全地从多个线程使用。 However, it is not safe when other code is writing the dictionary at the same time (which your code is doing).ConcurrentDictionary
is an easy solution to get going, but it may be no faster than your first version (I assume it's going to lock on every operation).ConcurrentDictionary
是一个简单的解决方案,但它可能不会比您的第一个版本快(我假设它会锁定每个操作)。 And a side note: Using a field that is not private (here the field is someDictionary
and we don't know if it's private
or not) as a lock
target is not recommended because theoretically external code could also decide to lock
it without your knowledge (practically this is not going to happen, but why not be theoretically correct as well?).附注:不建议使用非私有字段(这里的字段是
someDictionary
,我们不知道它是否是private
的)作为lock
目标,因为理论上外部代码也可以在您不知情的情况下决定lock
它(实际上这不会发生,但为什么在理论上也不正确呢?)。
If you use .NET 4 you can use ConcurrentDictionary
for thread safety.如果使用 .NET 4,则可以使用
ConcurrentDictionary
来确保线程安全。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.