2010-09-25 73 views
11

我们在生产环境中遇到了奇怪的错误,我们无法调试也无法注入日志记录代码。我试图找出这个,但下面的堆栈跟踪混淆了我。在什么情况下System.Collections.ArrayList.Add抛出IndexOutOfRangeException?

System.IndexOutOfRangeException: Index was outside the bounds of the array. 
    at System.Collections.ArrayList.Add(Object value) 
    at ... 

According to the MSDNAdd方法时才抛出NotSupportedException

我不知道这里发生了什么。你做?

+0

你可以发布一些完整的stacktrace吗? – shahkalpesh 2010-09-25 14:25:05

+3

只是猜测:ArrayList用于多线程操作? – 2010-09-25 14:28:28

+0

您可能能够通过在发生异常时在调试器中检查其他线程状态来确认并发错误。检查当时是否有其他人正在更换容器。 – 2010-09-25 15:47:59

回答

7

它归结为列举不是线程安全的。在一个列表迭代使用多线程添加项目没有下文同步,

List<TradeFillInfo> updatedFills = new List<TradeFillInfo>(); 
Parallel.ForEach (trades, (trade) => 
{ 
    TradeFillInfo fill = new TradeFillInfo(); 

    //do something 

    updatedFills.Add(fill); //NOTE:Adding items without synchronization 
}); 

foreach (var fill in updatedFills) //IndexOutOfRangeException here sometimes 
{ 
    //do something 
} 

时,在这种情况下,我不得不IndexOutOfRangeException发生的历史,updatedFills算遭破坏,后续迭代失败。围绕锁定语句包装Add()应该可以避免这种情况。

lock (updatedFills) 
{ 
    updatedFills.Add(fill); 
} 
19

当“尝试访问数组元素的索引超出数组边界的数组元素时,会引发IndexOutOfRangeException”。

请注意,ArrayList类不是线程安全的。在多线程场景中,竞争条件可能会导致ArrayList试图读取/写入超出其范围的索引处的支持数组。

示例:一个线程在另一个线程添加到集合的同时,减少了后备阵列的大小(可能通过调用TrimToSize)。现在,如果后备数组处于满负荷状态,则添加线程将尝试扩展其容量(通过分配新数组)以容纳新元素。同时TrimToSize调用然后反转这种效果。然后,当添加线程尝试写入数组时,其认为可用的索引将不再存在,从而导致抛出异常。

修复:使用线程安全结构,适合您的的情况。

11

这几乎可以肯定是一个并发问题......您可能有两个线程同时修改集合,并且ArrayList类不支持并发访问。发生竞态条件,这有时会导致其中一个线程尝试写入数组边界之外的位置。

尽力保护所有使用lock语句访问集合,或使用回收的同步包装(使用ArrayList.Synchronized法)

相关问题