Threadsafe foreach перечисление списков

Мне нужно перечислить хотя бы общие объекты IList < > . Содержимое списка может измениться, как при добавлении или удалении другими потоками, и это убьет мое перечисление с изменением коллекции, операция перечисления может не выполняться.

Каков хороший способ делать threadafe foreach на IList < > ? желательно без клонирования всего списка. Невозможно клонировать фактические объекты, на которые ссылается список.

Ответ 1

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

Ответ 2

Ваша проблема в том, что перечисление не позволяет IList изменять. Это означает, что вам нужно избегать этого при просмотре списка.

Приходят в голову несколько возможностей:

  • Клонировать список. Теперь у каждого счетчика есть своя копия для работы.
  • Сериализовать доступ к списку. Используйте блокировку, чтобы убедиться, что ни одна другая нить не может ее модифицировать во время ее перечисления.

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

Ответ 3

Вы найдете эту очень интересную тему.

Лучший подход зависит от ReadWriteResourceLock, который использует большие проблемы с производительностью из-за так называемой проблемы Convoy.

Лучшая статья, которую я нашел для обработки темы, - этот от Джеффри Рихтера, который раскрывает свой собственный метод для высокопроизводительного решения.

Ответ 4

Нет такой операции. Лучшее, что вы можете сделать, это


lock(collection){
    foreach (object o in collection){
       ...
    }
}

Ответ 5

Forech зависит от того, что коллекция не изменится. Если вы хотите перебирать коллекцию, которая может меняться, используйте нормальную конструкцию и будьте готовы к недетерминированному поведению. Блокировка может быть лучшей идеей, в зависимости от того, что вы делаете.

Ответ 6

ICollection MyCollection;
// Instantiate and populate the collection
lock(MyCollection.SyncRoot) {
  // Some operation on the collection, which is now thread safe.
}

От MSDN

Ответ 7

Итак, требования: вам нужно перечислить через IList < > без копирования, одновременно добавляя и удаляя элементы.

Не могли бы вы прояснить некоторые вещи? Есть ли вставки и удаления только в начале или конце списка? Если изменения могут возникать в любой точке списка, как должно вести себя перечисление, когда элементы удаляются или добавляются вблизи или по месту текущего элемента перечисления?

Это, безусловно, можно сделать, создав собственный объект IEnumerable с, возможно, целым индексом, но только если вы можете контролировать весь доступ к вашему объекту IList < > (для блокировки и поддержания состояния вашего перечисления). Но многопоточное программирование - это сложный бизнес в лучших обстоятельствах, и это сложный вероятный вопрос.

Ответ 8

Поведение по умолчанию для простой индексированной структуры данных, такой как связанный список, b-tree или хеш-таблица, необходимо перечислять в порядке от первого до последнего. Это не вызовет проблемы с вставкой элемента в структуру данных после того, как итератор уже прошел эту точку или вставить тот, который итератор будет перечислять после его поступления, и такое событие может быть обнаружено приложением и обработано, если приложение потребовало его. Чтобы обнаружить изменение в коллекции и выбросить ошибку во время перечисления, я мог только представить, была ли кто-то (плохая) идея делать то, что, по их мнению, требовало программиста. Действительно, Microsoft исправила свои коллекции для правильной работы. Они назвали свои блестящие новые несломанные коллекции ConcurrentCollections (System.Collections.Concurrent) в .NET 4.0.

Ответ 9

Оберните список в объект блокировки для чтения и записи. Вы можете даже итератировать с несколькими читателями сразу, если у вас есть подходящая блокировка, которая позволяет нескольким одновременно читателям, но и одному писателю (когда нет читателей).