}
Console.WriteLine(Thrd.Name + " завершен!");
// Уведомить о событии,
mre.Set();
}
}
class ManualEventDemo {
static void Main() {
ManualResetEvent evtObj = new ManualResetEvent(false);
MyThread mt1 = new MyThread("Событийный Поток 1", evtObj);
Console.WriteLine("Основной поток ожидает событие.");
// Ожидать уведомления о событии.
evtObj.WaitOne();
Console.WriteLine("Основной поток получил " +
"уведомление о событии от первого потока.");
// Установить событийный объект в исходное состояние.
evtObj.Reset();
mt1 = new MyThread("Событийный Поток 2", evtObj);
// Ожидать уведомления о событии.
evtObj.WaitOne();
Console.WriteLine("Основной поток получил " +
"уведомление о событии от второго потока.");
}
}
Ниже приведен результат выполнения рассматриваемой здесь программы, хотя у вас он может оказаться несколько иным.
Внутри потока Событийный Поток 1
Событийный Поток 1
Основной поток ожидает событие.
Событийный Поток 1
Событийный Поток 1
Событийный Поток 1
Событийный Поток 1
Событийный Поток 1 завершен!
Основной поток получил уведомление о событии от первого потока.
Внутри потока Событийный Поток 2
Событийный Поток 2
Событийный Поток 2
Событийный Поток 2
Событийный Поток 2
Событийный Поток 2
Событийный Поток 2 завершен!
Основной поток получил уведомление о событии от второго потока.
Прежде всего обратите внимание на то, что событие типа ManualResetEventпередается непосредственно конструктору класса MyThread. Когда завершается метод Run()из класса MyThread, он вызывает для событийного объекта метод Set(), устанавливающий этот объект в сигнальное состояние. В методе Main()формируется событийный объект evtObjтипа ManualResetEvent, первоначально устанавливаемый в исходное, несигнальное состояние. Затем создается экземпляр объекта типа MyThread, которому передается событийный объект evtObj. После этого основной поток ожидает уведомления о событии. А поскольку событийный объект evtObjпервоначально находится в несигнальном состоянии, то основной поток вынужден ожидать до тех пор, пока для экземпляра объекта типа MyThreadне будет вызван метод Set()устанавливающий событийный объект evtObjв сигнальное состояние. Это дает возможность основному потоку возобновить свое выполнение. Затем событийный объект устанавливается в исходное состояние, и весь процесс повторяется, но на этот раз для второго потока. Если бы не событийный объект, то все потоки выполнялись бы одновременно, а результаты их выполнения оказались бы окончательно запутанными. Для того чтобы убедиться в этом, попробуйте закомментировать вызов метода WaitOne()в методе Main().
Если бы в рассматриваемой здесь программе событийный объект типа AutoResetEventиспользовался вместо событийного объекта типа ManualResetEvent, то вызывать метод Reset()в методе Main()не пришлось бы. Ведь в этом случае событийный объект автоматически устанавливается в несигнальное состояние, когда поток, ожидающий данное событие, возобновляет свое выполнение. Для опробования этой разновидности события замените в данной программе все ссылки на объект типа ManualResetEventссылками на объект типа AutoResetEventи удалите все вызовы метода Reset(). Видоизмененная версия программы будет работать так же, как и прежде.
Еще одним классом, связанным с синхронизацией, является класс Interlocked. Этот класс служит в качестве альтернативы другим средствам синхронизации, когда требуется только изменить значение общей переменной. Методы, доступные в классе Interlocked, гарантируют, что их действие будет выполняться как единая, непрерываемая операция. Это означает, что никакой синхронизации в данном случае вообще не требуется. В классе Interlockedпредоставляются статические методы для сложения двух целых значений, инкрементирования и декрементирования целого значения, сравнения и установки значений объекта, обмена объектами и получения 64-разрядно-го значения. Все эти операции выполняются без прерывания.
Читать дальше