Что такое Microsoft.NET?

  35790931     

Автоматическая синхронизация



Автоматическая синхронизация

Атрибуты можно использовать для синхронизации доступа к методам экземпляра (нестатическим) и нестатическим полям класса. Доступ к статическим полям и методам не синхронизируется. Чтобы использовать эту возможность нужно создать класс, производный от класса System: :ContextBoundObject и применить к нему атрибут Synchronization (Синхронизация). Этот атрибут не применяется к отдельному полю или методу.
Данный атрибут находится в пространстве имен System :: Runtime :: Remoting :: Contexts (Система::Время выполнения:: Remoting::Контексты). Он описывает синхронизационные требования для экземпляра класса, к которому применяется. В конструктор SynchronizationAttribute можно передать одно из четырех значений, являющихся статическими полями класса SynchronizationAttribute: NONSUPPORTED, SUPPORTED (ПОДДЕРЖИВАЕМЫЙ), REQUIRED (ТРЕБУЕМЫЙ), REQUIRES_NEW. Пример Threading (Организация поточной обработки) на шаге 3 иллюстрирует, как это сделать.

using namespace System :: Runtime :: Remoting :: Contexts;
// использование пространства имен
// Система :: Время выполнения :: Remoting :: Контексты;
// SynchronizationAttribute :: REQUIRED (ТРЕБУЕМЫЙ) - 4
[Synchronization(4) ]
// [Синхронизация (4)]
public _gc _abstract class Broker :
// сборщик мусора - абстрактный класс Broker:
public ContextBoundObject
{
};

Общеязыковая среда времени выполнения CLR, чтобы удостовериться в том, что поток, в котором выполняются методы объекта, синхронизирован должным образом, должна отслеживать требования объекта по организации поточной обработки. Эти требования называются контекстом объекта. Если один объект должен быть синхронизирован, а другой нет, то говорят, что они находятся в двух отдельных контекстах. Общеязыковая среда времени выполнения CLR должна овладеть замком синхронизации от имени кода, когда поток, который выполняет не нуждающийся в синхронизации метод объекта, начинает выполнять нуждающийся в синхронизации метод другого объекта. Общеязыковая среда времени выполнения CLR знает, что в этом случае нужно сделать, потому что она может сравнить требования первого объекта к организации поточной обработки с требованиями второго объекта, просто сравнивая их контексты.
Об объектах, разделяющих одинаковое состояние, говорят как о живущих в том же самом контексте. Например, два объекта, которые не должны быть синхронизированы, могут совместно использовать один и тот же контекст. ContextBoundOb j ect и контексты обсуждаются более подробно в разделе, посвященном контекстам.
Используя это интуитивное понятие контекста, мы можем теперь объяснить назначение различных атрибутов синхронизации Synchronization (Синхронизация). NOT_SUPPORTED означает, что класс не может поддерживать синхронизацию своих методов экземпляров и нестатических полей и поэтому не должен создаваться в контексте синхронизации. REQUIRED (ТРЕБУЕМЫЙ) значит, что класс требует синхронизации доступа к своим методам и полям экземпляров. Однако, если поток уже синхронизирован, он может использовать существующий замок синхронизации и жить в существующем контексте синхронизации. REQUIRES_NEW означает, что требуется не только синхронизация, но также и доступ к методам и полям экземпляра должен происходить с уникальным замком синхронизации и в отдельном контексте. Атрибут SUPPORTED (ПОДДЕРЖИВАЕМЫЙ) применяется, если класс не требует синхронизации доступа к методам и полям экземпляра; для него не нужно создавать новый контекст.
Можно также передать булев флажок в конструктор, чтобы указать, требуется ли реентерабельность. Если флажок установлен (т.е. реентерабельность требуется), синхронизируются обратные вызовы из методов. В противном случае синхронизируются только вызовы методов.
Используя атрибут Synchronization (Синхронизация) в методе Brocker :: Reserve (Брокер :: Резерв), можно отказаться от Monitor :: Enter (Монитор :: Войти) и Monitor :: Exit (Монитор :: Выйти).
Так же, как и в шаге 2, в этом примере иллюстрируется попытка дважды зарезервировать последний свободный номер в гостинице. Вот как выглядит выдача при выполнении этого примера:

Added Boston Presidential Hotel with one room.
Thread 13 starting a new thread.
Thread 28 starting.
Thread 29 starting.
Reserving for Customer 1 at the Boston Presidential Hotel on
12/12/2001 12:00:00 AM for 3 days
Thread 28 entered Broker::Reserve
Thread 28 finds the room is available in Broker::Reserve
Thread 28 left Broker::Reserve
Reservation for Customer 1 has been booked
Reservationld = 1 ReservationRate = 10000
ReservationCost = 30000
Comment = OK
Reserving for Customer 2 at the Boston Presidential Hotel on



12/13/2001 12:00:00 AM for 1 days
Thread 29 entered Broker::Reserve
Thread 29 left Reserve.
Reservation for Customer 2 could not be booked
Room not available
Done !

Пере вод такой:

Добавлена Бостонская Президентская гостиница с одним номером.
Поток 13 стартовал новый поток.
Поток 28 стартовал.
Поток 29 стартовал.
Резервирование для Клиента 1 в Бостонской Президентской гостинице
на
12/12/2001 12:00:00 AM в течение 3 дней
Поток 28 вошел в Брокер::Резерв
Поток 28 находит, что номер доступен в Брокер::Резерв
Поток 28 вышел из Брокер::Резерв
Резервирование для Клиента 1 было заказано
Reservationld = 1
ReservationRate = 10000
ReservationCost = 30000
Комментарий = OK
Резервирование для Клиента 2 в Бостонской Президентской гостинице на
12/13/2001 12:00:00 AM в течение 1 дня
Поток 29 вошел в Брокер::Резерв
Поток 29 вышел из Резерв.
Резервирование для Клиента 2 не могло быть заказано
Номер не доступен
Сделано!

Как и в предыдущем случае, второй поток не может выполнить метод Reserve (Резерв), пока поток, который начал выполнение первым, не закончится. Номер резервируется только раз.
Отличие этого автоматического подхода заключается в том, что синхронизируется доступ ко всем методам класса независимо от того, нуждаются они в этом или нет. Доступ к другим совместно используемым данным с помощью других методов данного класса также блокируется. Такое поведение получается независимо от желания программиста.
Обращаем внимание читателя на то, что в любой определенный момент только один поток может выполнять какой-нибудь метод класса. Предположим, что мы добавляем к классу еще один метод под названием CancelReservation. Если какой-нибудь поток вызвал метод CancelReservation, то блокируются все другие потоки, делающие попытки выполнять другие методы класса, включая и метод MakeReservation.
Для программы, которая производит резервирование номеров в гостинице, это желательное поведение, так как нежелательно, чтобы метод MakeReservation пытался использовать структуру данных в момент ее изменения. В некоторых ситуациях, однако, такое поведение нежелательно и уменьшает производительность из-за ненужного блокирования. Увеличение числа конфликтов может стать помехой для масштабирования, так как блокируются не только определенные, нуждающиеся в синхронизации области.
Использовать атрибуты проще, чем критические секции. Не нужно заботиться о подробностях правильной реализации синхронизации. С другой стороны, в результате мы получаем поведение, которое уменьшает масштабируемость. Разные приложения и различные части одного и того же приложения могут получать выгоду от использования того подхода, который в данном конкретном случае имеет больше смысла.




Содержание раздела