如何在多线程应用程序中找出修改foreach循环中的项目的函数或目标?
我不断收到错误“收集已修改;枚举操作可能无法执行”。我没有删除或添加任何项目到for循环中的通用列表。 我想知道它是如何被修改的。 这样做的最佳方式是什么?
由于
答案 0 :(得分:7)
等一下 - 我想我们都错过了这一点。
集合类不是线程安全的。如果多个线程正在访问集合而没有线程锁定,那么您需要修复它。这是一个特别阴险的问题,因为它可以正常工作 [编辑 - 或抛出可预测的异常] 99.999%的时间,0.001%的时间它会做一些完全不可预测的事情,几乎不可能重现。
一种简单的方法是在任何代码访问集合的地方周围使用lock {}语句。这可能是轻微的矫枉过正,但这是最安全的计划。对于迭代,您可以锁定整个循环,或者如果您不想阻止其他长的线程,只需将其锁定足够长的时间来制作快照:
object[] snap;
lock (list)
{
snap = list.ToArray();
}
foreach (object x in snap) ...
答案 1 :(得分:2)
这不是一个直接的答案,只是一个可能有帮助的建议 - 在迭代期间可能会修改集合的多线程情况下,我通常使用ToArray方法创建列表的快照以进行迭代:
foreach (object x in list.ToArray()) ...
答案 2 :(得分:1)
用ObservableCollection替换集合,将事件附加到修改并在调试器中打破它们(或捕获堆栈跟踪等)。
答案 3 :(得分:0)
执行此操作的最佳方法是不将集合公开给可能会更改它的许多类。将它作为一个特定类的私有,然后只有该类的方法可能会改变它。
否则,您需要从集合类创建派生类,并覆盖可以更新集合的所有方法。在所有覆盖中设置断点。
答案 4 :(得分:0)
将全局集合的内容复制到更严格的范围变量以保护外部插入数据是否可行?
答案 5 :(得分:0)
你应该能够设置一个异常断点,然后只需要通过每个线程来查看哪一个修改了该集合。在任何情况下,如果集合在多个线程之间共享,则需要正确同步。
答案 6 :(得分:0)
您可能希望尝试使用ObservableCollection类。有一些例子可以使这个线程安全。
答案 7 :(得分:0)
您也可以尝试更改集合的类名,以查看它的引用位置。