如何在迭代(C#)时将ListItem添加到列表中?

时间:2011-09-10 13:46:23

标签: c# multithreading mono thread-safety gtk

我有一个小应用程序,它使用BackgroundWorker随时处理IEnumerator<T> list

代码基本上是这样的:

while(true){
    foreach(T item in list){
       // Process each item and send process
       // Add an object in child List ( List<T1> item.Result )
    }
    Thread.Sleep(500);
}

现在我有一个按钮和一个文本框,它将直接添加到IEnumerator。

问题是,在我添加按钮后,后台工作人员继续处理它当前处理的项目,但在完成该项目后将停止。它不会继续。

如何安全地将项目添加到列表中而不影响后台工作者?在后台工作者旁边也会添加对象。应该解决这个问题的方法是什么?

谢谢

3 个答案:

答案 0 :(得分:6)

让后台工作程序迭代原始列表的副本,而不是列表本身。

 while (true)
 {
       foreach (T item in new List<T>( list ))
       {
          ....
       }
       Thread.Sleep(500);
 }

如果在枚举时尝试修改集合,枚举器将抛出异常。来自docs

  

只要收集仍然存在,枚举器仍然有效   不变。如果对集合进行了更改,例如添加,   修改或删除元素,枚举器是不可恢复的   无效,下次调用MoveNext或Reset会抛出一个   InvalidOperationException异常。如果在之间修改了集合   MoveNext和Current,Current返回它设置的元素,   即使枚举器已经失效。

答案 1 :(得分:2)

你应该首先学习有关多线程编程的基础知识,所以,在这里。

尝试一下这个:

// shared queue
ConcurrentQueue<T> queue = new ConcurrentQueue<T>();
// shared wait handle
AutoResetEvent autoEvent = new AutoResetEvent();

这里的队列比列表更好,因为它允许你添加和删除元素而不用担心当前元素的索引 - 你只需Enqueue()个项目,而且{{1另一方面。使用来自Dequeue()命名空间的类,它会自动为您处理线程安全访问(并且由于复杂的原因,您可能希望稍后阅读,比简单的System.Collections.Concurrent更快。)

现在,前台线程:

lock()

这里的魔法部分是我们// schedule the work queue.Enqueue(itemOfWork); // and wake up our worker autoEvent.Set(); 上调用的Set()(是的,WaitHandleAutoResetEvent的实现)。它唤醒了一直在等待同步事件触发的单个线程,而不使用像WaitHandle这样丑陋的结构。对Thread.Sleep()的调用几乎总是多线程代码中出错的标志!

好的,最后一部分 - 工作者线程。这里没有太多变化:

Sleep()

答案 2 :(得分:1)

您可能需要使用“lock”关键字来防止从两个代码位置同时访问共享的“list”变量。

http://msdn.microsoft.com/en-us/library/c5kehkcz(v=vs.71).aspx