【问题标题】:is it safe to apply double-checked locking to Dictionary?对字典应用双重检查锁定是否安全?
【发布时间】:2012-12-30 15:54:39
【问题描述】:

Dictionary 应用双重检查锁定是否安全?

即从不同线程调用TryGetValue 和其他“get/contains”方法是否安全? (不调用其他非 get 方法)。

upd 收藏对 N 个读者和 1 个作者来说是安全的吗?假设在循环 10 中,线程尝试使用双重检查锁定访问带有键 X 的元素,如果访问,它们只是将其删除。在某些时候,我确实从另一个线程添加了带有键 X 的元素(使用锁)。我希望只有一位读者应该获取此元素并将其删除。

upd2,关于答案,所以我的问题令人困惑。其实我问了两个问题:

  1. 从不同线程调用TryGetValue 和其他“get/contains”方法是否安全? (不调用其他非 get 方法)。
  2. N 位读者和 1 位作者的收藏是否安全?

第一个问题的答案是肯定的,第二个问题的答案是否定的。

所以有时apply double-checked locking 是安全的,有时却不是。这取决于您是否同时写入集合。

【问题讨论】:

  • 根据规格,分析器是肯定的:msdn.microsoft.com/en-us/library/xfhwa508.aspx
  • 我不知道您需要为作为只读数据结构(又名不可变类型)访问的数据结构使用锁,该数据结构本质上是线程安全的。如果您从不更改它,则根本不需要锁。
  • 如果您使用的是 .NET 4.0 或更高版本,您可以使用此 ConcurrentDictionary。
  • @AloisKraus 使用双重检查锁定的要点是在不需要赢得几纳秒的情况下不使用锁定,我在编写 HFT 时确实需要它们。
  • ConcurrentDictionary 是一个几乎无锁的数据结构。在引擎盖下,它确实使用了类似的模式来实现几乎无锁的更新。

标签: c#


【解决方案1】:

我假设您正在谈论通用的 Dictionary<TKey, TValue> 类。该课程对 N 个读者或 1 个作者是安全的。因此,只要您不修改它,您就可以拥有想要从中读取的任意数量的线程,而无需锁定。

如果线程可能想要修改字典,您必须同步对它的访问。我建议ReaderWriterLockSlim

【讨论】:

  • 谢谢,为什么使用ReaderWriterLockSlim 而不是一般的lock?会更快吗?
  • 我真的不同意这样做是安全的。看我的回答。
  • @javapowered 因为它针对编写者需要排他锁而读者不需要的情况进行了优化。一个简单的锁实现不允许并发读者。
  • @usr 这个答案说你可以有一个作家多个读者,而不是“和”,并且文档确实支持该断言。
  • @Jim Mischel 我误读了答案。我必须被编辑,这样我才能恢复反对票。明天我会检查是否可以恢复它。
【解决方案2】:

这是不安全的,因为它没有被证明是安全的。你不能有一个作家和 N 个读者。

这是来自文档的适用句子:

一个字典可以同时支持多个阅读器, 只要集合没有被修改。

实际上,如果您使用 Reflector 查看 Dictionary,您会发现它是不安全的,但这不是重点。关键是您不能依赖未记录的属性,因为它们可以随时更改,从而将错误引入生产中,而没人知道。

您也无法测试它是否安全。它可能适用于您的盒子并在其他地方损坏。这是线程错误的本质。不值得。

【讨论】:

  • 你看文档了吗? “一个 Dictionary 可以同时支持多个阅读器,只要不修改集合即可。”
  • @phoog,多个读取器,但不能同时使用一个并发写入器。那是有区别的。
  • 是的,我明白了——我阅读了与 Jim Mischel 的回答有关的回答,而不是与问题有关的回答,因为我最近阅读了他的回答而不是问题。如果您编辑答案,我将能够删除我的反对票。
  • @phoog 已编辑。我误读了那个词,引起了相当大的混乱。
猜你喜欢
  • 1970-01-01
  • 2011-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多