【发布时间】:2009-07-22 18:44:44
【问题描述】:
我正在使用 foreach 循环遍历要处理的数据列表(处理后删除所述数据 - 这是在锁内)。此方法时不时会导致 ArgumentException。
捕获它会很昂贵,所以我尝试追踪问题,但我无法弄清楚。
我已经切换到一个 for 循环,问题似乎已经消失了。有人可以解释发生了什么吗?即使有异常消息,我也不太明白幕后发生了什么。
为什么 for 循环显然有效?是我错误地设置了 foreach 循环还是什么?
这几乎就是我的循环的设置方式:
foreach (string data in new List<string>(Foo.Requests))
{
// Process the data.
lock (Foo.Requests)
{
Foo.Requests.Remove(data);
}
}
和
for (int i = 0; i < Foo.Requests.Count; i++)
{
string data = Foo.Requests[i];
// Process the data.
lock (Foo.Requests)
{
Foo.Requests.Remove(data);
}
}
编辑:for* 循环处于这样的 while 设置中:
while (running)
{
// [...]
}
编辑:根据要求添加了有关异常的更多信息。
System.ArgumentException: Destination array was not long enough. Check destIndex and length, and the array's lower bounds
at System.Array.Copy (System.Array sourceArray, Int32 sourceIndex, System.Array destinationArray, Int32 destinationIndex, Int32 length) [0x00000]
at System.Collections.Generic.List`1[System.String].CopyTo (System.String[] array, Int32 arrayIndex) [0x00000]
at System.Collections.Generic.List`1[System.String].AddCollection (ICollection`1 collection) [0x00000]
at System.Collections.Generic.List`1[System.String]..ctor (IEnumerable`1 collection) [0x00000]
编辑:锁定的原因是有另一个线程添加数据。另外,最终会有多个线程在处理数据(所以如果整个设置有误,请指教)。
编辑:很难选择一个好的答案。
我发现 Eric Lippert 的评论值得,但他并没有真正回答(无论如何都对他的评论投了赞成票)。
Pavel Minaev、Joel Coehoorn 和 Thorarin 都给出了我喜欢并投票赞成的答案。 Thorarin 还额外花费了 20 分钟来编写一些有用的代码。
我可以接受所有 3 并让它分裂声誉但是唉。
Pavel Minaev 是下一个应得的,因此他获得了荣誉。
感谢好心人的帮助。 :)
【问题讨论】:
-
请提供您获得的 ArgumentException 的前几帧(即来自 FCL 本身)。
-
“for”循环正在工作,因为你是幸运。你的线程逻辑完全被破坏了,所以这可能会随机失败。通过更改为 for 循环,您已经巧妙地更改了某些处于竞争状态且不再遇到问题的操作的时间;任何事情都可能导致它回来。如果您想拥有一个在多个线程上读取和修改的集合,那么您需要非常非常小心让您的锁定正确。否则,正如您所经历的那样,它只会随机失败。考虑使用读写锁。
-
@Eric Lippert:为什么这是评论而不是答案?很有帮助。
-
锁定的原因是什么?上下文是什么? ASP.NET?是否有其他线程访问此数据?
-
@eric 我猜这不是时机。如果没有删除任何项目(即列表中没有项目),for 循环只会遍历列表中的所有项目。如果一个被删除,则列表中的下一个将不会被访问,所以总而言之,只有一半的项目将被删除。而每次删除一个项目时,foreach 循环都会重新开始迭代
标签: c# exception foreach for-loop