Синхронизация данных для многопоточности
Обновлен: Ноябрь 2007
Если несколько потоков могут вызывать свойства и методы отдельного объекта, эти вызовы необходимо синхронизовать. В противном случае поток может прервать операцию другого потока, и объект будет иметь неверное состояние. Класс, элементы которого защищены от подобных прерываний, называется потокобезопасным.
Общеязыковая инфраструктура содержит несколько способов синхронизации доступа к статическим элементам и элементам экземпляров.
Синхронизованные области кода. Для синхронизации только требуемых блоков кода в целях улучшения производительности можно воспользоваться классом Monitor или поддержкой компилятора для этого класса.
Синхронизация вручную.Можно использовать объекты синхронизации, предоставленные в библиотеке классов .NET Framework. См. раздел Обзор примитивов синхронизации, в котором обсуждается класс Monitor.
Синхронизованные контексты. Можно использовать SynchronizationAttribute для разрешения простой автоматической синхронизации для объектов ContextBoundObject.
Свойство Synchronized. Немногие классы, такие как Hashtable и Queue, предоставляют свойство Synchronized, которое возвращает потокобезопасную оболочку для экземпляра класса. См. раздел Коллекция и синхронизация (потокобезопасность).
Общеязыковая среда выполнения содержит модель, в которой классы делятся на категории, которые можно синхронизировать различными путями в соответствии с необходимыми требованиями. В следующей таблице представлены виды поддержки синхронизации, доступные для полей и методов в заданной категории синхронизации.
Категория |
Глобальные поля |
Статические поля |
Статические методы |
Поля экземпляра |
Методы экземпляра |
Определенные блоки кода |
---|---|---|---|---|---|---|
Без синхронизации |
Нет |
Нет |
Нет |
Нет |
Нет |
Нет |
Синхронизованный контекст |
Нет |
Нет |
Нет |
Да |
Да |
Нет |
Синхронизованные области кода |
Нет |
Нет |
Только если помечены |
Нет |
Только если помечены |
Только если помечены |
Синхронизация вручную |
Manual |
Manual |
Manual |
Manual |
Manual |
Manual |
Без синхронизации
Этот вариант используется по умолчанию для объектов. Любой поток может обратиться к любому методу или полю в любое время. К этим объектам может единовременно обращаться только один поток.
Синхронизация вручную
Библиотека классов .NET Framework предоставляет ряд классов для синхронизации потоков. See Обзор примитивов синхронизации.
Синхронизованные области кода
Можно использовать класс Monitor или ключевое слово компилятора для синхронизации блоков кода, методов экземпляра и статических методов. Данная поддержка не распространяется на синхронизованные статические поля.
Visual Basic и C# поддерживают маркировку блоков кода ключевым словом определенного языка: оператор lock в C# или оператор SyncLock в Visual Basic. Если код выполняется потоком, происходит попытка получить блокировку. Если блокировка уже была получена другим потоком, поток блокируется до того момента, как блокировка станет доступной. Если поток выходит из синхронизированного блока кода, блокировка освобождается независимо от способа выхода потока из блокировки.
Примечание. |
---|
Операторы lock и SyncLock реализованы с помощью методов Monitor.Enter и Monitor.Exit, так что другие методы Monitor могут быть использованы вместе с ними в синхронизованной области. |
Также можно дополнить метод с помощью MethodImplAttribute и MethodImplOptions.Synchronized, что приведет к тому же эффекту, что и использование Monitor или любого ключевого слова компилятора для блокировки всей основной части метода.
Thread.Interrupt может быть использован для вывода потока из операций блокирования, таких как ожидание доступа к синхронизированной области кода. Thread.Interrupt также используется для вывода потоков из операций, таких как Thread.Sleep.
Важное примечание. |
---|
Не блокируйте тип, то есть typeof(MyType) in C#, GetType(MyType) в Visual Basic или MyType::typeid в C++, чтобы защитить методы static methods (методы Shared в Visual Basic). Вместо этого используйте закрытый статический объект. Так же не используйте this в C# (Me в Visual Basic) для блокирования методов экземпляра. Вместо этого используйте закрытый объект. Класс или экземпляр могут быть заблокированы другим кодом, что может привести к взаимоблокировкам или проблемам, связанным с производительностью. |
Поддержка компилятора
Visual Basic и C# поддерживают ключевое слово языка, которое использует Monitor.Enter и Monitor.Exit для блокировки объекта. Visual Basic поддерживает оператор SyncLock; C# поддерживает оператор lock.
В обоих случаях блокировка, назначенная с помощью lock или SyncLock, снимается автоматически, если в блоке кода создано исключение. Компиляторы языка C# и Visual Basic выдают блокировку try/finally с помощью Monitor.Enter в начале работы, а блокировку finally с помощью Monitor.Exit. Если в блокировке lock или SyncLock создано исключение, запускается обработчик finally, разрешающий операцию очистки.
Синхронизованный контекст
Для синхронизации всех полей и методов экземпляров можно воспользоваться атрибутом SynchronizationAttribute любого объекта ContextBoundObject. Все объекты в одном контекстном домене имеют одинаковую блокировку. Доступ к методам и полям предоставляется нескольким потокам, но только один из них может обращаться к методам или полям одновременно.
См. также
Основные понятия
Обзор примитивов синхронизации