C# 使用字典线程是否安全?
这里是我的方法的两个变体,它返回一个与枚举值(保存在字典中)关联的字符串。第一个变体速度较慢,但线程安全,第二个更快,但我不知道它是否线程安全。第一:C# 使用字典线程是否安全?,c#,.net,thread-safety,C#,.net,Thread Safety,这里是我的方法的两个变体,它返回一个与枚举值(保存在字典中)关联的字符串。第一个变体速度较慢,但线程安全,第二个更快,但我不知道它是否线程安全。第一: string GetStringForEnum (SomeEnum e) { string str = null; lock (someDictionary) //someDictionary is not used anywhere else (only in this method) { if (!someDictionar
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;
}
第二种变体:
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;
}
第二个变体不是每次都使用“锁定”,但它是否是线程安全的?如果使用.NET 4,则可以使用
ConcurrentDictionary
实现线程安全。onDictionary
中有一节介绍线程安全:
字典(TKey,TValue)
可以支持多个阅读器
同时,只要集合未被修改。即便如此,
通过集合枚举本质上不是线程安全的
程序在枚举与写入争用的罕见情况下
访问时,必须在整个枚举期间锁定集合。
允许多个线程访问集合以进行读取
在编写时,您必须实现自己的同步
有关线程安全的替代方案,请参见TKey的ConcurrentDictionary,
t值)
因此:
- 可以从多个线程安全使用,因为它是只读的。但是,当其他代码同时编写字典时(您的代码正在编写字典),这是不安全的
- 除非锁定字典,否则添加值永远不会安全
- 使用
是一个简单的解决方案,但可能不会比第一个版本快(我假设它会锁定每个操作)ConcurrentDictionary
还有一个旁注:不建议使用非私有的字段(这里的字段是
someDictionary
,我们不知道它是否是private
)作为lock
目标,因为理论上外部代码也可以在您不知情的情况下决定lock
它(实际上这不会发生,但为什么理论上不正确呢?)这里有两个问题:
-即使字典没有在其他地方使用,也不建议这样做。这是一个理论上的论点,但dictionary类的(未来)代码可能会锁定自身lock(someDictionary)
没有锁。我假设这是对如果(!someDictionary(e,out str))
的调用。这根本不是线程安全的,您的读取可能会被另一个线程中的写入中断。这可能会导致各种错误(索引超出范围,空引用)。错误将非常罕见(=难以重现)TryGetValue()
!someDictionary(e,out str)
进行小的更正。您说“TryGetValue可以从多个线程安全使用,因为它是只读的。”,但这只适用于“只要不修改集合”。OP给出的例子清楚地表明,他实际上是在更新字典,这使得在锁外使用TryGetValue
不安全。不安全。对于你的其余答案:+1。@Steven:我可能应该说得很清楚。因此编辑了答案,感谢反馈。“但是(未来)Dictionary类的代码可能会锁定自身。“。如果字典这样做,它将打破一个强有力的指导方针,这也将是一个突破性的变化。因此,可以安全地假设字典永远不会锁定自己。@Steven-你是对的,就像人们所说的“理论”。最佳做法是使用一个你尽可能控制和隐藏的实例。@HenkHolterman:我必须这样做假设我在编写LOB应用程序时非常务实,只需锁定私有集合(如果可能)。另一方面,在为可重用库编写代码时,我非常严格。这都是关于上下文;-)是的,我强烈建议使用System.Collections.Concurrent命名空间中的集合,而不是使用锁。如果不可能,则使用ReaderWriterLockSlim。