以线程安全的方式枚举列表

时间:2012-04-10 07:12:57

标签: c# .net multithreading thread-safety

假设我在类中有一个列表,将在多线程场景中使用。

public class MyClass
{
     List<MyItem> _list= new List<MyItem>();
     protected object SyncRoot { 
      get {
         return ((IList)_list).SyncRoot;
        }
     }

     public void Execute1()
     {
        lock(SyncRoot)
        {
             foreach(var item in _list) DoSomething(item);
        }
     }

     public void Execute2()
     {
         Item[] list;
         lock(SyncRoot)
         {
            list=_list.ToArray();
         }
           for(var i=0;i<list.Length;i++) DoSomething(list[i]);
      }
}

方法 Execute1 是以线程安全方式枚举列表的“常规”方式。但是 Execute2 呢?这种方法仍然是线程安全的吗?

2 个答案:

答案 0 :(得分:2)

在两种情况下,访问(副本)列表都是线程安全的。但是,MyItem元素当然不会以任何方式同步。

第二种形式看起来有点贵,但是当DoSomething()正在运行时,它将允许在原始版本上添加/删除。该数组就像一种快照,如果符合您的要求,它可能会很有用。请注意,您也可以使用ToList()

答案 1 :(得分:1)

只要_list的每个其他用法也使用相同的lock语句进行保护,它就是安全的。您将对列表进行独占访问,复制其内容,然后处理副本(由于作用域,您也可以访问该列表)。乍一看有点浪费,但在某些情况下是合法的做法。