【问题标题】:Defending against race conditions in System.Collections.Concurrent.ConcurrentDictionary防御 System.Collections.Concurrent.ConcurrentDictionary 中的竞争条件
【发布时间】:2012-05-12 16:40:45
【问题描述】:

.NET ConcurrentDictionary 容易受到可能导致意外数据的竞争条件的影响,正如 at the bottom of this MSDN article. 所解释的那样,我假设有几个因素需要考虑。

问:我应该如何编写不易受到可能导致数据丢失的竞争条件的代码?

在我的场景中,我有一个输入流,其索引始终在增加 (n++)。我的想法是,如果出现竞争情况,我可以detect missing data 并重新发送它。另一方面,我不知道可能有更好的方法来做到这一点。

【问题讨论】:

  • 避免 GetOrAdd() 和 AddOrUpdate() ?
  • 答案取决于你要做什么。你有什么类型的任务?
  • @gabba - 我的任务是从各种来源读取安全日志数据。每个日志条目都有一个不断增加的索引。有关更多信息,请参阅更新的问题/链接

标签: c# multithreading .net-4.0 race-condition concurrentdictionary


【解决方案1】:

人们必须注意并发集合(不限于 .net)的一个普遍缺陷,即 单个操作可能是线程安全的,但操作序列不是原子的。我的意思如下:假设这种情况,我有一个带有Check 和Add 操作的并发集合,两者都是原子的。

我想要做的是检查一个值是否存在,如果不存在,添加它。所以我可以这样写:

if(!collection.Check(value)) 
{
    collection.Add(value);
}

虽然这两个操作都是原子的,但上述顺序不是,因为一个线程可能会在检查和添加之间被另一个线程中断,从而导致结果不一致。因此,整个序列应该是原子的,例如将其包装在 lock 语句中。

lock(locker)
{
   if(!collection.Check(value)) 
   {
       collection.Add(value);
   }
}

【讨论】:

  • 锁不会造成巨大的性能损失吗? (与自旋锁相比)。如果可以检测丢失的数据并在发生数据丢失时重新传输它会更好吗?
  • @makerofthings7:是的,在需要非常高性能的应用程序中,这可能是一个性能问题,可以使用替代方法,如无锁版本或自旋锁,因为受保护的实际代码是相当小。
  • 我认为使用双重检查锁定更为理想。 if(!collection.Check(value)) { lock(locker) { if(!collection.Check(value)) { collection.Add(value); } } }
  • @Gabba 感谢您提供有关双重检查锁定的提示...我现在正在学习它。 en.wikipedia.org/wiki/Double-checked_locking
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-21
  • 2019-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-07
相关资源
最近更新 更多