C# 4.0 полное руководство - 2011
Шрифт:
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 mtl = new MyThread("Tick", tt) ;
MyThread mt2 = new MyThread("Tock", tt) ;
mtl.Thrd.Join; mt2.Thrd.Join;
Console.WriteLine("Часы
}
}
Эта версия программы дает такой же результат, как и предыдущая. Синхронизируемый метод не определен в открытом классе и не вызывается для открытого объекта, поэтому применение оператора lock или атрибута MethodlmplAttribute зависит от личных предпочтений. Ведь и тот и другой дает один и тот же результат. Но поскольку ключевое слово lock относится непосредственно к языку С#, то в примерах, приведенных в этой книге, предпочтение отдано именно ему.
ПРИМЕЧАНИЕ
Не применяйте атрибут MethodlmplAttribute в открытых классах или экземплярах открытых объектов. Вместо этого пользуйтесь оператором lock, чтобы заблокировать метод для закрытого объекта, как пояснялось ранее.
Применение мьютекса и семафора
В большинстве случаев, когда требуется синхронизация, оказывается достаточно и оператора lock. Тем не менее в некоторых случаях, как, например, при ограничении доступа к общим ресурсам, более удобными оказываются механизмы синхронизации, встроенные в среду .NET Framework. Ниже рассматриваются по порядку два таких механизма: мьютекс и семафор.
Мьютекс
Мьютекс представляет собой взаимно исключающий синхронизирующий объект. Это означает, что он может быть получен потоком только по очереди. Мьютекс предназначен для тех ситуаций, в которых общий ресурс может быть одновременно использован только в одном потоке. Допустим, что системный журнал совместно используется в нескольких процессах, но только в одном из них данные могут записываться в файл этого журнала в любой момент времени. Для синхронизации процессов в данной ситуации идеально подходит мьютекс.
Мьютекс поддерживается в классе System. Threading.Mutex. У него имеется несколько конструкторов. Ниже приведены два наиболее употребительных конструктора.
public Mutex
public Mutex(bool initiallyOwned)
В первой форме конструктора создается мьютекс, которым первоначально никто не владеет. А во второй форме исходным состоянием мьютекса завладевает вызывающий поток, если параметр ini tiallyOwned имеет логическое значение true. В противном случае мьютексом никто не владеет.
Для того чтобы получить мьютекс, в коде программы следует вызвать метод WaitOne для этого мьютекса. Метод WaitOne
public bool WaitOne ;
Метод WaitOne ожидает до тех пор, пока не будет получен мьютекс, для которого он был вызван. Следовательно, этот метод блокирует выполнение вызывающего потока до тех пор, пока не станет доступным указанный мьютекс. Он всегда возвращает логическое значение true.
Когда же в коде больше не требуется владеть мьютексом, он освобождается посредством вызова метода ReleaseMutex , форма которого приведена ниже.
public void ReleaseMutex
В этой форме метод ReleaseMutex освобождает мьютекс, для которого он был вызван, что дает возможность другому потоку получить данный мьютекс.
Для применения мьютекса с целью синхронизировать доступ к общему ресурсу упомянутые выше методы WaitOne и ReleaseMutex используются так, как показано в приведенном ниже фрагменте кода.
Mutex myMtx = new Mutex;
// ...
myMtx.WaitOne ; // ожидать получения мьютекса // Получить доступ к общему ресурсу.
myMtx.ReleaseMutex; // освободить мьютекс
При вызове метода WaitOne выполнение соответствующего потока приостанавливается до тех пор, пока не будет получен мьютекс. А при вызове метода ReleaseMutex мьютекс освобождается и затем может быть получен другим потоком. Благодаря такому подходу к синхронизации одновременный доступ к общему ресурсу ограничивается только одним потоком.
В приведенном ниже примере программы описанный выше механизм синхронизации демонстрируется на практике. В этой программе создаются два потока в виде классов IncThreadn DecThread, которым требуется доступ к общему ресурсу: переменной SharedRes . Count. В потоке IncThread переменная SharedRes . Count инкрементируется, а в потоке DecThread — декрементируется. Во избежание одновременного доступа обоих потоков к общему ресурсу SharedRes . Count этот доступ синхронизируется мьютексом Mtx, также являющимся членом класса SharedRes.
// Применить мьютекс.
using System;
using System.Threading;
//В этом классе содержится общий ресурс(переменная Count),
// а также мьютекс (Mtx), управляющий доступом к ней. class SharedRes {
public static int Count = 0;
public static Mutex Mtx = new Mutex;
}
// В этом потоке переменная SharedRes.Count инкрементируется, class IncThread { int num;