Синхронизация коллекций

В ICollection присутствует одно средство, которого недостает его обобщенному аналогу, а именно — обеспечение многопоточной синхронизации для всех коллекций. По умолчанию большинство типов коллекций не синхронизировано. Для определения того, синхронизирована ли коллекция, служит свойство Is Synchronized. В большинстве случаев, включая System.Array, ответ будет отрицательным (false). Однако иногда синхронизация требуется при обращении к коллекции из нескольких потоков.

Существует пара способов управлять синхронизацией коллекций, возвращающих false из ICollection.IsSynchronized. Основной способ предусматривает использование свойства ICollection.SyncRoot, возвращающего объект, который впоследствии можно применить с System.Monitor — обычно с помощью оператора lock, — чтобы защитить доступ к коллекции.

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

Выбор способа реализации синхронизации — классический пример компромиссного инженерного решения, которое приходится принимать при проектировании новых коллекций, реализующих ICollection. Синхронизацию можно реализовать внутри коллекции, но тогда клиенты, которым она не нужна, будут нести излишние затраты.

Синхронизацию также можно вынести наружу, реализовав ICollection.SyncRoot, но тогда на клиента возлагается обязанность правильно управлять синхронизацией. Делая тот или иной выбор, следует учитывать особенности домена приложения.

В некоторых случаях типы коллекций просто возвращают для ICollection.SyncRoot ссылку this. Поэтому лучше никогда не синхронизировать доступ к коллекции, передавая ссылку на нее напрямую System.Monitor. Вместо этого всегда используйте объект, полученный через свойство SyncRoot, даже несмотря на то, что оно может в действительности вернуть this.

В качестве альтернативы ручному управлению SyncLock большинство необобщенных типов коллекций из стандартной библиотеки реализуют метод Synchronized, который возвращает объект-оболочку коллекции, управляющий блокировкой синхронизации. Аналогичный шаблон можно попробовать применить при создании собственных типов коллекций.

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

Если требуется синхронизация внутри коллекций, используемых в многопоточной системе, настоятельно рекомендуется использовать типы коллекций из System.Collections.Concurrent. Эти типы были добавлены в .NET 4.0 командой платформы параллельных вычислений Microsoft, и их техника блокировки отлично настроена на обеспечение эффективности в многопоточных средах с параллелизмом.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100