2

How do I find out which function or target is modifying the items in a foreach loop in a multithreaded application?

I continously keep getting the error "Collection was modified; enumeration operation may not execute". I'm not removing or adding any items to the generic list within the for loop. I want to find out how it is getting modified. What is the best way to do this?

Thanks

4

8 回答 8

7

等一下——我想我们都错过了重点。

集合类不是线程安全的。如果集合被多个线程访问而没有线程锁定,那么您需要修复它。这是一个特别隐蔽的问题,因为它会在 99.999% 的情况下正常工作[编辑 - 或抛出可预测的异常],而在 0.001% 的情况下,它会做一些完全不可预测且几乎不可能重现的事情。

一种简单的方法是在任何代码访问集合的每个地方都使用 lock{} 语句。这可能有点矫枉过正,但这是最安全的计划。对于迭代,您可以锁定整个循环,或者如果您不想长时间阻塞其他线程,只需将其锁定足够长的时间以制作快照:

object[] snap;
lock (list)
{
   snap = list.ToArray();
}
foreach (object x in snap) ...
于 2009-04-21T13:34:46.130 回答
2

This is not a direct answer, just a suggestion that might help - in a multithreaded situation where a collection might get modified during iteration, I usually use the ToArray method to create a snapshot of the list for iteration:

foreach (object x in list.ToArray()) ...
于 2009-04-21T13:15:48.440 回答
1

Replace the collection with an ObservableCollection, attach events to modifications and break on them in the debugger (or capture stack trace etc.).

于 2009-04-21T13:18:42.270 回答
0

The best way to do this is to not expose the collection to many classes which could possibly change it. Make it private to one particular class, then only the methods of that class could possibly change it.

Otherwise, you would need to create a derived class from the collection class, and override all the methods that could update the collection. Set breakpoints at all the overrides.

于 2009-04-21T13:13:42.780 回答
0

Would it be feasible to copy the contents of the global collection to a more tightly scoped variable to protect outside meddling with the data?

于 2009-04-21T13:14:12.920 回答
0

您应该能够设置异常断点,然后只需遍历每个线程即可查看哪个线程修改了集合。在任何情况下,如果集合在多个线程之间共享,则需要正确同步。

于 2009-04-21T13:22:47.097 回答
0

您可能想为此尝试ObservableCollection类。也有一些使该线程安全的示例。

于 2009-04-21T13:24:08.857 回答
0

您也可以尝试更改您的集合的类名,以查看所有引用的位置。

于 2009-04-21T13:25:44.077 回答