ReadOnlyCollection <T>Потокобезопасность - PullRequest
9 голосов
/ 22 декабря 2011

Документация для ReadOnlyCollection (of T) гласит:

A ReadOnlyCollection(Of T) может поддерживать несколько читателей одновременно, если коллекция не изменена. Тем не менее, перечисление через коллекцию по сути не является потокобезопасной процедурой . Чтобы гарантировать безопасность потоков во время перечисления, вы можете заблокировать коллекцию во время всего перечисления. Чтобы обеспечить доступ к коллекции из нескольких потоков для чтения и записи, необходимо реализовать собственную синхронизацию.

Мой вопрос касается жирной части:

  1. почему перечисление через коллекцию не является поточно-ориентированным
  2. каковы возможные последствия, и
  3. Какие способы обхода обычно используются?

Ответы [ 2 ]

7 голосов
/ 22 декабря 2011

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

Теперь, чтобы перейти к вашему вопросу, это просто декоратор, доступный только для чтения, из IList, поставляемого во время сборки. Поэтому код, создавший коллекцию ReadOnlyCollection, может изменить исходный список со всеми вытекающими последствиями для многопоточного доступа.

Таким образом, перечисление через коллекцию было бы поточно-ориентированным, если бы коллекция действительно была доступна только для чтения; но так как он не только для чтения, он не является потокобезопасным. Учитывая количество вашей репутации, я уверен, что вам не интересно, почему перечисление через коллекцию, не предназначенную только для чтения, не является потокобезопасным.

Что касается предложенного вами обходного пути, вы можете либо использовать блокировку, либо использовать принцип «ничего не блокировать» (или блокировать как можно меньше) и делать истинную копию только для чтения. список.

EDIT

Я перечитываю свой ответ много месяцев спустя (благодаря комментарию Асинквейта) и понимаю, что должен был ответить на все вопросы ОП, не делая предположений на основании его репутации. ОП уже получил свой ответ, но я сделаю это ради будущих читателей.

Перечисление через коллекцию, не предназначенную только для чтения, изначально не является поточно-ориентированным по тем же причинам, по которым даже в однопоточном сценарии вы не можете изменять коллекцию при ее перечислении. (ConcurrentModificationException в Java, InvalidOperationException в C #.) В однопоточном сценарии вы можете убедиться, что ваш код перечисления не пытается каким-либо образом изменить коллекцию, но в многопоточном сценарии один поток может перечислять коллекцию, пока другой поток может изменять его одновременно.

3 голосов
/ 22 декабря 2011

В этой статье MSDN говорится: "Экземпляр универсального класса ReadOnlyCollection всегда доступен только для чтения. Коллекция, доступная только для чтения, - это просто коллекция с оболочкой, предотвращающей изменение коллекции. "

Поэтому я считаю, что итерация не является потокобезопасной, поскольку она внутренне использует обычную не поточно-безопасную коллекцию объектов.

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

...