Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответы ОСиСП.doc
Скачиваний:
69
Добавлен:
11.05.2015
Размер:
1.78 Mб
Скачать

Упрощение кода c# при помощи оператора lock

Поскольку последовательность «вызов метода Monitor.Enter — обращение к защищенному ресурсу — вызов метода Monitor.Exit» используется очень часто, в С# предусмотрен особый синтаксис для упрощения кода. Два следующие фрагмента кода идентичны:

private void SomeMethod()

{

lock (this)

{

// Доступ к объекту...

}

}

private void SomeMethod()

{

Object temp = this;

Monitor.Enter(temp);

try

{

// Доступ к объекту...

}

finally

{

Monitor.Exit(temp);

}

}

Оператор lockупрощает классTransaction. Взгляните на новое, усовершенствованное свойство LastTransaction; временная переменная больше не нужна.

internal sealed class Transaction

{

// Поле, указывающее время выполнения последней транзакции.

private DateTime timeOfLastTransaction;

public void PerformTransaction()

{

lock (this)

{

// Выполнение транзакции...

// Запись времени выполнения последней транзакции.

timeOfLastTransaction = DateTime.Now;

}

}

// Отмена блокировки объекта.

// Неизменяемое свойство, возвращающее время последней транзакции,

public DateTime LastTransaction

{

get

{

lock (this)

{

// Блокировка объекта.

return timeOfLastTransaction;

// Возвращение даты и времени.

}

// Отмена блокировки объекта.

}

}

}

Кроме того, что код стал короче и проще, оператор lock гарантирует вызов метода MonitorExit, а значит, блок синхронизации освобождается, даже если в блоке lock возникает исключение. Использовать обработку исключений в механизмах синхронизации потоков следует всегда — это позволит корректно отменять блокировки. Если используется оператор lockязыкаC#, компилятор автоматически создает нужный код.

Внимание! Приведенный выше код демонстрирует, как в Microsoft первоначально предполагали использовать блоки синхронизации объекта. Однако у этого кода есть серьезный недостаток.

Способ синхронизации статических членов, предлагаемый Microsoft

Класс Transaction показывает, как синхронизировать доступ к полям экземпляров объектов. Но что, если в типе определено несколько статических полей и статических методов, которые обращаются к этим полям? В этом случае у вас нет экземпляра типа в куче, а значит, нет блока синхронизации, который можно использовать, и нет ссылки на объект, которую можно передать методам Enter и Exit объекта Monitor.

На рис. 24-1 видно, что у объекта A, объектаBи объектаCуказатель на объект-тип ссылается на Туре-Т (объект-тип). Иначе говоря, у всех трех объектов один тип. Объект-тип также является объектом в куче и, как и у остальных объектов, у него два служебных члена: индекс блока синхронизации и указатель на объект-тип. Это значит, что блок синхронизации можно связывать с объектом-типом, а ссылку на объект-тип — передавать методам Monitor, Enter, TryEnter и Exit. В приведенной ниже версии класса Transaction все члены сделаны статическими, а метод PerformTransaction и свойство LastTransaction были изменены — они демонстрируют, как в Microsoft первоначально предлагали разработчикам синхронизировать доступ к статическим членам.

internal static class Transaction

{

// Поле, указывающее время выполнения последней транзакции,

private static DateTime timeOfLastTransaction;

public static void PerformTransaction()

{

lock (typeof(Transaction))

{

// Enter the type object's lock

// Выполнение транзакции...

// Запись времени выполнения последней транзакции.

timeOfLastTransaction = DateTime.Now;

} // Отмена блокировки объекта.

}

// Неизменяемое свойство, возвращающее время последней транзакции.

public static DateTime LastTransaction

{

get

{

lock (typeof(Transaction))

{

// Блокировка объекта-типа.

// Возвращение даты и времени.

return timeOfLastTransaction;

} // Отмена блокировки объекта.

}

}

}

В этом коде статический метод и аксессор get свойства не могут ссылаться на объект this, так как он не доступен для статических членов. Вместо этого оператору lock передается ссылка на тип объекта-типа (полученный при помощи оператора typeof языка С#).

Внимание!Приведенный выше код демонстрирует, как в Microsoft первоначально предполагали использовать блоки синхронизации объекта. Однако у этого кода есть серьезный недостаток, поэтому не следует копировать этот код в собственные проекты.