刚开始用C#的线程写程序,碰着个关于锁的奇怪问题。望高人指教。一个程序有两个线程。
先是一个公共的 ArrayList list. 里面有很多的元素(是比较复杂的类实例)线程A
 不定时 的向这个list中插入元素。线程B
每时间间隔遍历list中的元素输出。基本代码如下。{
  while(true)
  lock(list)
  {
    foreach(aClass aa in list)
    {
      name = aa.name;
    }
    Thread.Sleep(500);
  }
}我在测试的时候,让A线程向list插入1000个元素。结果就偶尔会在B线程中报出foreach的错误,说是在遍历的时候,list已经被修改???!!!这是怎么回事??? 我已经加锁的啊 ??完全茫然,望达人指教。多谢。ps:新人一个,没啥分,只能期盼好心的人了

解决方案 »

  1.   

    这样写试试
    lock( list.SyncRoot )
    {
         //插入数据
    }lock( list.SyncRoot )
    {
        //遍历集合
    }
      

  2.   

     lock(list) 
    你这里的 list 对象是在什么地方创建的?
      

  3.   

    在A线程中,向list插入数据的时候也需要加锁
      

  4.   

    这个方法考虑过,但这个list复制个副本进行遍历的方法,和加锁,将读写操作串行化的方法相比谁的效率高呢??这个list运行起来大概有几十兆。
      

  5.   


    list的定义 public List<DTUClient> logicalDUTList = new List<DTUClient>();没找到有SyncRoot这个属性还是我理解有误??
      

  6.   

    再仔细想了下,我这还不能用副本的方法。因为我这里要对list中元素的某些属性进行修改,不是纯粹的读。当然没有增删元素的操作。
      

  7.   

    加锁可以,但你出错还有一个可能,就是别用foreach这种形式写
    最好换成
    if(list.items.count>0)
    {
    //取出一个
    //执行代码
    }
      

  8.   

    冒泡
    还能接到分么?lock(list)
      {
        foreach(aClass aa in list)
        {
          name = aa.name;
        }
        Thread.Sleep(500);
      } 
    把Thread.Sleep放在里面?是什么用意?别的获得索的机会有多少?是不是应该放在外面?
      

  9.   


    范型里没有SyncRoot
    你可以使用ReaderWriterLock
      

  10.   

    让遍历等待,插完后通知可以开始遍历
    lock( list.SyncRoot ) 

         //插入数据 
       Monitor.Pulse(list.SyncRoot ); 
    } lock( list.SyncRoot ) 

       Monitor.Wait(list.SyncRoot ); 
        //遍历集合 
    }
      

  11.   

    能详细的指教下,foreach有什么缺点么?我理解的是foreach就是系统去实现了个for循环,由于长度在一开始就定了,所以在循环的过程中不能进行元素的增删操作。在我看来foreach就是个功能单一的for循环,就是书写简单些。