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

发布于 2024-12-04 04:56:12 字数 493 浏览 1 评论 0原文

我有一个小型应用程序,它使用BackgroundWorker 来处理IEnumerator;始终列出

代码基本上是这样的:

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。

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

如何安全地将项目添加到列表中而不影响后台工作人员?除了后台工作人员之外,还可以向项目添加对象。对此应该采取什么解决方案?

谢谢

I have a small application that using BackgroundWorker to process the IEnumerator<T> list at all time.

The code basically like this:

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);
}

Now I have a button and a textbox, which will add directly to the IEnumerator.

The problem is that after I add button, the backgroundworker continue to process it's currently processing Item, but will stop after finish that item. It does not continue.

How can I safely add an Item to the list without affect the backgroundworker? Beside the background worker also do adding objects to the item. What should be the solution for this?

Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

坏尐絯℡ 2024-12-11 04:56:13

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

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

如果您在枚举集合时尝试修改集合,则枚举器将引发异常。来自文档

只要集合存在,枚举器就保持有效
不变。如果对集合进行更改,例如添加,
修改或删除元素,枚举器是不可恢复的
无效并且下次调用 MoveNext 或 Reset 会抛出
无效操作异常。如果集合在以下时间之间被修改
MoveNext 和 Current,Current 返回它所设置的元素,
即使枚举器已经失效。

Have the background worker iterate over a copy of the original list, not the list itself.

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

If you attempt to modify a collection while enumerating over it, the enumerator will throw an exception. From the docs:

An enumerator remains valid as long as the collection remains
unchanged. If changes are made to the collection, such as adding,
modifying, or deleting elements, the enumerator is irrecoverably
invalidated and the next call to MoveNext or Reset throws an
InvalidOperationException. If the collection is modified between
MoveNext and Current, Current returns the element that it is set to,
even if the enumerator is already invalidated.

夕嗳→ 2024-12-11 04:56:13

您应该首先学习有关多线程编程的基础知识,所以,就这样吧。

尝试一下:

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

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

现在,前台线程:

// schedule the work
queue.Enqueue(itemOfWork);
// and wake up our worker
autoEvent.Set();

这里最神奇的部分是在 WaitHandle 上调用的 Set()(是的,AutoResetEvent 是一个WaitHandle)。它唤醒一直在等待同步事件触发的单个线程,而不使用诸如 Thread.Sleep() 之类的丑陋结构。对 Sleep() 的调用几乎总是多线程代码中错误的标志!

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

while(true)
{
  // wait for the signal
  autoEvent.WaitOne();
  T item;
  // grab the work item
  queue.TryDequeue(out item);

  // handle the item here;
}

You should learn the basics about multi-threaded programming first, so, here it goes.

Try something along this:

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

The queue is better here than the list, because it allows you to add and remove elements from it without worrying about the index of the current element - you just Enqueue() items on the other and, and Dequeue() them on the other. Use a class from System.Collections.Concurrent namespace, which handles thread-safe access for you automatically (and, due to complicated reasons you might want to read on later, is faster than a simple lock()).

Now, the foreground thread:

// schedule the work
queue.Enqueue(itemOfWork);
// and wake up our worker
autoEvent.Set();

The sprinkly-magical part here is the Set() invoked on our WaitHandle (yes, AutoResetEvent is an implementation of a WaitHandle). It wakes up a single thread that has been waiting for the synchronization event to fire, without using such ugly constructs as Thread.Sleep(). A call to Sleep() is almost always a sign of a mistake in multithreaded code!

Ok, for the last part - worker thread. Not many changes here:

while(true)
{
  // wait for the signal
  autoEvent.WaitOne();
  T item;
  // grab the work item
  queue.TryDequeue(out item);

  // handle the item here;
}
故人如初 2024-12-11 04:56:13

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

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

You probably need to use the "lock" keyword to prevent simultaniously accessing the shared "list" variable from both places of code.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文