Как сделать ENumerable операции протектора безопасными SynchronizedCollection? - PullRequest
0 голосов
/ 26 апреля 2019

Когда я использую SynchronizedCollection, я могу поймать исключение

System.InvalidOperationException
Collection was modified; enumeration operation may not execute.

в foreach цикле.

Если вы посмотрите на исходный код класса SynchronizedCollection, а именно в GetEnumeratorметод (есть два из них, на самом деле один является явной реализацией интерфейса), вы увидите это:

List<T> items;

IEnumerator IEnumerable.GetEnumerator()
{
    return ((IList)this.items).GetEnumerator();
}

public IEnumerator<T> GetEnumerator()
{
    lock (this.sync)
    {
        return this.items.GetEnumerator();
    }
}

Возвращает перечислитель внутреннего List, который не является потокобезопасным !

Правка.Я не спрашиваю, что я могу сделать в параллельных ситуациях.Я спрашиваю

Как сделать потокобезопасным?

Ответы [ 2 ]

1 голос
/ 26 апреля 2019

Я думаю, что есть два решения для этого:

  1. Используйте ConcurrentBag или другую коллекцию в пространстве имен System.Collections.Concurrent. (Обратите внимание, что элементы в ConcurrentBag не будут упорядочены.)
  2. Создание снимка при получении данных.

Второй способ намного безопаснее с точки зрения производительности.

Если вы используете .NetCore, ImmutableList - это лучший способ для моментального снимка, позволяющий избежать проблемы мелкого копирования.

0 голосов
/ 26 апреля 2019

Я использовал класс SynchronizedCollection и использовал foreach (var element in this.items) yield return element; Вот публичный новый IEnumerator GetEnumerator ()

использовались конструкторы из базовых классов, и этого было достаточно, чтобы сделать его потокобезопасным

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...