C#使用集合时的线程安全的最佳实践(已经不是并发)

时间:2013-04-10 21:09:52

标签: c# multithreading collections synchronization thread-safety

我的问题更像是我想与其他人确认的事情,所以我确信我得到了正确的答案。 如果要进行非线程安全操作(例如枚举集合),最好的方法是调用Synchronized方法(如果该集合存在)。

例如:var syncAL = ArrayList.Synchronized( myAL );

然后你可以做一些无忧无虑的事情:

foreach (var item in syncAL){
  // Do something
}

现在我个人并不真正使用ArrayLists,它只是用于示例,但对于常规List,Synchronized方法不存在,所以这里最好的做法是:

lock (list.SyncRoot){
 // non thread-safe operation, e.g:
 list.ForEach(item => Console.WriteLine(item.ToString()));
}

因为你当然可以创建自己的任意对象,但如果你在多个类中使用一些集合对象,你需要确保你使用相同的对象来锁定所有这些类这似乎是一种非常舒适的方式。

我想确保它真的是最好的做法,在我添加我为团队编写的开发提示之前,我没有遗漏任何东西:)

我对此的理解来源: MSDN SyncRoot

2 个答案:

答案 0 :(得分:4)

  
    

然后你可以做一些无忧无虑的事情:

  
foreach (var item in syncAL){
  // Do something
}

没有。来自MSDN

  
    

通过集合枚举本质上不是一个线程安全的过程。即使集合是同步的,

  

关于核心问题:

  

我想确保它确实是最好的做法

不,这是一种过时的做法。请注意,SyncRoot仅限于ICollectionICollection<T>不支持。较新的集合(List<>)不支持它,这是您的主要线索。

答案 1 :(得分:3)

在ArrayList.Synchronized包装器中包装集合不会使枚举线程安全,MSDN明确说明:

...即使集合同步,其他线程仍然可以修改集合,这会导致枚举器抛出异常。

因此,最佳方法仍然是锁定SyncRoot,或使用System.Collections.Concurrent命名空间中的线程安全集合。

ArrayList.Synchronized的内部实现只会创建内部类SyncArrayList的实例,它将锁定SyncRoot以进行任何操作,如下所示:

  public override int Add(object value)
  {
    lock (this._root)
      return this._list.Add(value);
  }