none
请问多线程List<T>操作的问题 RRS feed

  • 问题

  • 存在两个线程操作同一个List<T>

    List<int> T1 = new List<int>

    其中一个线程

    foreach(var t in T1)

    {

      ....操作

    }

     

    另外一个线程负责

    T1.Add()与 T1.Remove()

     

    现在的问题是当我其中一个线程在读取的时候,另外一线程增加或删除集合内容后,foreach 抛出 集合同内容已修改 的异常。请问如何处理

    2010年8月20日 10:21

答案

  • foreach内部用的是List.Iterator,当List的内容改变时,Iterator会立即失效,再次访问iterator就会抛异常。

    你可以考虑把foreach改成for (int i = 0; i < T1.Count; ++i),这样应该就没问题了。


    Shuhai Shen - I love programming, travel and photographing. Welcome to my blog: http://leonax.net
    2010年8月20日 12:51
  • 两个知识点,

    首先,foreach (对枚举器的包装)过程是不能增加或者删除集合即不能出现这样的代码 foreach(T item in oneList<T>) { oneList<T>.Remove(item); }

    其次,多线程,显然你需要考虑线程同步。对 List<T> 进行从头到尾枚举过程不是线程安全的,像你这种读与写竞争的情况,最简单的实现是在整个枚举期间锁定集合,比如

    // 读线程
    lock(theList<T>) {
    foreach(T item in oneList<T>) { // read each item}
    }

    // 写线程
    lock(theList<T>) {
    oneList<T>.Add(obj);
    }

    此外,使用 for 或者 while 只能解决问题1,线程同步依然需要考虑

     


     

    问题要简单,错误须详细@错误/异常/堆栈信息+操作系统+软件版本+all the context of the issue Hope Helpful | http://www.leoworks.net

    2010年8月20日 14:08

全部回复

  • foreach内部用的是List.Iterator,当List的内容改变时,Iterator会立即失效,再次访问iterator就会抛异常。

    你可以考虑把foreach改成for (int i = 0; i < T1.Count; ++i),这样应该就没问题了。


    Shuhai Shen - I love programming, travel and photographing. Welcome to my blog: http://leonax.net
    2010年8月20日 12:51
  • 两个知识点,

    首先,foreach (对枚举器的包装)过程是不能增加或者删除集合即不能出现这样的代码 foreach(T item in oneList<T>) { oneList<T>.Remove(item); }

    其次,多线程,显然你需要考虑线程同步。对 List<T> 进行从头到尾枚举过程不是线程安全的,像你这种读与写竞争的情况,最简单的实现是在整个枚举期间锁定集合,比如

    // 读线程
    lock(theList<T>) {
    foreach(T item in oneList<T>) { // read each item}
    }

    // 写线程
    lock(theList<T>) {
    oneList<T>.Add(obj);
    }

    此外,使用 for 或者 while 只能解决问题1,线程同步依然需要考虑

     


     

    问题要简单,错误须详细@错误/异常/堆栈信息+操作系统+软件版本+all the context of the issue Hope Helpful | http://www.leoworks.net

    2010年8月20日 14:08
  • 加锁的方式好像不太适合。对于读的进程来讲,是无时无刻都在读的。如果加锁肯定会对插入与删除产生延迟。
    2010年8月20日 16:07
  • 加锁的方式好像不太适合。对于读的进程来讲,是无时无刻都在读的。如果加锁肯定会对插入与删除产生延迟。

    当然要锁住,要不可能得到脏数据
    http://feiyun0112.cnblogs.com/
    2010年8月24日 1:44
    版主
  • 定义 ArrayList 用它的Synchronized 方法

    ArrayList T1 = new ArrayList();

    T1.Add();...

    ArrayList.Synchronized (T1);

    foreach(var t in T1)

    {

      ....操作

    }

    2013年4月12日 3:29