Книга: C# 4.0: полное руководство

Применение атрибута MethodlmplAttribute

Применение атрибута MethodlmplAttribute

Метод может быть полностью синхронизирован с помощью атрибута MethodlmplAttribute. Такой подход может стать альтернативой оператору lock в тех случаях, когда метод требуется заблокировать полностью. Атрибут MethodlmplAttгibute определен в пространстве имен System.Runtime.CompilerServices. Ниже приведен конструктор, применяемый для подобной синхронизации:

public MethodlmplAttribute(MethodlmplOptions methodlmplOptions)

где methodlmplOptions обозначает атрибут реализации. Для синхронизации метода достаточно указать атрибут MethodlmplOptions.Synchronized. Этот атрибут вызывает блокировку всего метода для текущего экземпляра объекта, доступного по ссылке this. Если же метод относится к типу static, то блокируется его тип. Поэтому данный атрибут непригоден для применения в открытых объектах или классах.

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

// Использовать атрибут MethodlmplAttribute
// для синхронизации метода.
using System;
using System.Threading;
using System.Runtime.CompilerServices;
//Вариант класса TickTock, переделанный с целью
// использовать атрибут MethodlmplOptions.Synchronized,
class TickTock {
  /* Следующий атрибут полностью синхронизирует метод Tick(). */
  [MethodImplAttribute(MethodImplOptions.Synchronized)]
  public void Tick(bool running) {
    if (!running) { // остановить часы
      Monitor.Pulse(this); // уведомить любые ожидающие потоки
      return;
    }
    Console.Write("тик ");
    Monitor.Pulse(this); // разрешить выполнение метода Tock()
    Monitor.Wait(this);    //    ожидать завершения метода Tock()
  }
  /* Следующий атрибут полностью синхронизирует метод Тоск(). */
  [MethodImplAttribute(MethodImplOptions.Synchronized)]
  public void Tock(bool running) {
    if (!running) { // остановить часы
      Monitor.Pulse(this); // уведомить любые ожидающие потоки
      return;
    }
    Console.WriteLine("так");
    Monitor.Pulse(this); // разрешить выполнение метода Tick()
    Monitor.Wait(this);    //    ожидать завершения метода Tick()
  }
}
class MyThread {
  public Thread Thrd;
  TickTock ttOb;
  // Сконструировать новый поток.
  public MyThread(string name, TickTock tt) {
    Thrd = new Thread(this.Run);
    ttOb = tt;
    Thrd.Name = name;
    Thrd.Start();
  }
  // Начать выполнение нового потока,
  void Run() {
    if (Thrd.Name == "Tick") {
      for (int i = 0; i < 5; i++) ttOb.Tick(true);
      ttOb.Tick(false);
    }
    else {
      for (int i = 0; i < 5; i++) ttOb.Tock(true);
      ttOb.Tock(false);
    }
  }
}
class TickingClock {
  static void Main() {
    TickTock tt = new TickTock();
    MyThread mt1 = new MyThread("Tick", tt);
    MyThread mt2 = new MyThread("Tock", tt);
    mt1.Thrd.Join();
    mt2.Thrd.Join();
    Console.WriteLine("Часы остановлены");
  }
}

Эта версия программы дает такой же результат, как и предыдущая. Синхронизируемый метод не определен в открытом классе и не вызывается для открытого объекта, поэтому применение оператора lock или атрибута MethodlmplAttribute зависит от личных предпочтений. Ведь и тот и другой дает один и тот же результат. Но поскольку ключевое слово lock относится непосредственно к языку С#, то в примерах, приведенных в этой книге, предпочтение отдано именно ему.

----------------------------

ПРИМЕЧАНИЕ

Не применяйте атрибут MethodImplAttribute в открытых классах или экземплярах открытых объектов. Вместо этого пользуйтесь оператором lock, чтобы заблокировать метод для закрытого объекта, как пояснялось ранее.

----------------------------

Оглавление книги


Генерация: 1.164. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз