При каких обстоятельствах System.Collections.ArrayList.Add создает исключение IndexOutOfRangeException? - PullRequest
14 голосов
/ 25 сентября 2010

Мы столкнулись со странной ошибкой в ​​производственной среде, которую мы не можем ни отлаживать, ни вводить в журнал. Я пытаюсь понять это, но следующая трассировка стека смущает меня.

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

В соответствии с MSDN Add метод должен только выбросить NotSupportedException.

Понятия не имею, что здесь происходит. Вы?

Ответы [ 3 ]

19 голосов
/ 25 сентября 2010

IndexOutOfRangeException генерируется, когда «сделана попытка получить доступ к элементу массива с индексом, который находится за пределами массива».

Обратите внимание, что класс ArrayList не является потокобезопасным. Возможно, что в многопоточных сценариях условия гонки приведут к ArrayList попытке чтения / записи в резервный массив с индексами, которые находятся за пределами его диапазона.

Пример: один поток уменьшает размер базового массива (возможно, посредством вызова TrimToSize) одновременно с добавлением другого потока в коллекцию. Теперь, если резервный массив работает на полную мощность, добавляющий поток будет пытаться расширить свою емкость (выделив новый массив) для размещения нового элемента. Одновременный TrimToSize вызов затем отменяет этот эффект. Затем, к тому моменту, когда добавляющий поток попытается записать в массив, индекс, который он считал доступным , больше не будет доступен, что вызовет исключение.

Исправлено: Используйте потокобезопасные конструкции, соответствующие вашей ситуации.

11 голосов
/ 25 сентября 2010

Это почти наверняка проблема параллелизма ... Возможно, у вас есть два потока, которые изменяют коллекцию одновременно, а класс ArrayList не предназначен для поддержки одновременного доступа.Возникает состояние гонки, которое иногда приводит к тому, что один из потоков пытается выполнить запись в позиции за пределами массива.

Попробуйте защитить все обращения к коллекции с помощью операторов lock или используйте синхронизированныйупаковщик коллекции (по методу ArrayList.Synchronized)

10 голосов
/ 17 марта 2016

Это сводится к тому, что список не является потокобезопасным.Возникла исключительная ситуация IndexOutOfRangeException при итерации по списку после добавления элементов с использованием нескольких потоков без синхронизации, как показано ниже,

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
}

В этом случае счетчик updatedFills повреждени последующая итерация не удалась.Обертывание Add () вокруг оператора блокировки должно предотвратить это.

lock (updatedFills)
{
    updatedFills.Add(fill);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...