Информация об изменениях

Сообщение Re: баг в .NET? от 02.05.2017 1:29

Изменено 02.05.2017 1:38 nikov

Re: баг в .NET?
Здравствуйте, Kesular, Вы писали:

K>Время от времени, в интеграционных тестах возникает вот такое исключение:


K>

K>An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll

K>Additional information: Collection was modified; enumeration operation may not execute.

K>Похоже, баг где-то во внутренностях фреймворка?

Нет, скорее всего, это race condition в тестах. Иногда один поток модифицирует коллекцию, IEnumerator для которой в это время перебирается (с помощью MoveNext или foreach) в другом потоке. При изменении коллекции все живые энумераторы инвалидируются, и начинают бросать такое исключение.

См. документацию:

An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException.

The enumerator does not have exclusive access to the collection; therefore, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.

Re: баг в .NET?
Здравствуйте, Kesular, Вы писали:

K>Время от времени, в интеграционных тестах возникает вот такое исключение:


K>

K>An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll

K>Additional information: Collection was modified; enumeration operation may not execute.

K>Похоже, баг где-то во внутренностях фреймворка?

Нет, скорее всего, это race condition в тестах. Иногда один поток модифицирует коллекцию, IEnumerator для которой в это время перебирается (с помощью MoveNext или foreach) в другом потоке. При изменении коллекции все живые энумераторы инвалидируются, и начинают бросать такое исключение.

См. документацию:

An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException.

The enumerator does not have exclusive access to the collection; therefore, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.


Кроме рекомендуемой здесь ручной синхронизации, можно воспользоваться готовыми решениями из пространства имён System.Collections.Concurrent. См, например, ConcurrentBag.GetEnumerator():

The enumeration represents a moment-in-time snapshot of the contents of the bag. It does not reflect any updates to the collection after GetEnumerator was called. The enumerator is safe to use concurrently with reads from and writes to the bag.