Kniga-Online.club
» » » » Герберт Шилдт - C# 4.0: полное руководство

Герберт Шилдт - C# 4.0: полное руководство

Читать бесплатно Герберт Шилдт - C# 4.0: полное руководство. Жанр: Программирование издательство -, год 2004. Так же читаем полные версии (весь текст) онлайн без регистрации и SMS на сайте kniga-online.club или прочесть краткое содержание, предисловие (аннотацию), описание и ознакомиться с отзывами (комментариями) о произведении.
Перейти на страницу:

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

Применение атрибута 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, чтобы заблокировать метод для закрытого объекта, как пояснялось ранее.

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

Применение мьютекса и семафора

В большинстве случаев, когда требуется синхронизация, оказывается достаточно и оператора lock. Тем не менее в некоторых случаях, как, например, при ограничении доступа к общим ресурсам, более удобными оказываются механизмы синхронизации, встроенные в среду .NET Framework. Ниже рассматриваются по порядку два таких механизма: мьютекс и семафор.

Мьютекс

Мьютекс представляет собой взаимно исключающий синхронизирующий объект. Это означает, что он может быть получен потоком только по очереди. Мьютекс предназначен для тех ситуаций, в которых общий ресурс может быть одновременно использован только в одном потоке. Допустим, что системный журнал совместно используется в нескольких процессах, но только в одном из них данные могут записываться в файл этого журнала в любой момент времени. Для синхронизации процессов в данной ситуации идеально подходит мьютекс.

Мьютекс поддерживается в классе System.Threading.Mutex. У него имеется несколько конструкторов. Ниже приведены два наиболее употребительных конструктора.

public Mutex()

public Mutex(bool initiallyOwned)

В первой форме конструктора создается мьютекс, которым первоначально никто не владеет. А во второй форме исходным состоянием мьютекса завладевает вызывающий поток, если параметр ini tiallyOwned имеет логическое значение true. В противном случае мьютексом никто не владеет.

Для того чтобы получить мьютекс, в коде программы следует вызвать метод WaitOne() для этого мьютекса. Метод WaitOne() наследуется классом Mutex от класса Thread.WaitHandle. Ниже приведена его простейшая форма.

public bool WaitOne();

Метод WaitOne() ожидает до тех пор, пока не будет получен мьютекс, для которого он был вызван. Следовательно, этот метод блокирует выполнение вызывающего потока до тех пор, пока не станет доступным указанный мьютекс. Он всегда возвращает логическое значение true.

Когда же в коде больше не требуется владеть мьютексом, он освобождается посредством вызова метода ReleaseMutex(), форма которого приведена ниже.

public void ReleaseMutex()

В этой форме метод ReleaseMutex() освобождает мьютекс, для которого он был вызван, что дает возможность другому потоку получить данный мьютекс.

Для применения мьютекса с целью синхронизировать доступ к общему ресурсу упомянутые выше методы WaitOne()  и ReleaseMutex() используются так, как показано в приведенном ниже фрагменте кода.

Mutex myMtx = new Mutex();

// ...

myMtx.WaitOne() ; // ожидать получения мьютекса

            // Получить доступ к общему ресурсу.

myMtx.ReleaseMutex(); // освободить мьютекс

При вызове метода WaitOne() выполнение соответствующего потока приостанавливается до тех пор, пока не будет получен мьютекс. А при вызове метода ReleaseMutex() мьютекс освобождается и затем может быть получен другим потоком. Благодаря такому подходу к синхронизации одновременный доступ к общему ресурсу ограничивается только одним потоком.

Перейти на страницу:

Герберт Шилдт читать все книги автора по порядку

Герберт Шилдт - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки kniga-online.club.


C# 4.0: полное руководство отзывы

Отзывы читателей о книге C# 4.0: полное руководство, автор: Герберт Шилдт. Читайте комментарии и мнения людей о произведении.


Уважаемые читатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.

  • 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
  • 2. Просьба отказаться от оскорблений, угроз и запугиваний.
  • 3. Просьба отказаться от нецензурной лексики.
  • 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.

Надеемся на Ваше понимание и благоразумие. С уважением, администратор kniga-online.


Прокомментировать
Подтвердите что вы не робот:*
Подтвердите что вы не робот:*