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

События синхронизации и дескрипторы ожидания

Использование блокировки или монитора полезно для предотвращения одновременного выполнения блоков кода, но эти структуры не позволяют одному потоку передавать события в другой. Для этого требуются события синхронизации — объекты, обладающие одним их двух состояний (с сигналом или без сигнала), применяющиеся для активации и приостановки потоков. Потоки можно приостанавливать, заставляя их ожидать события синхронизации без сигнала, и активировать, меняя состояние события на состояние с сигналом. Если поток попытается ожидать события, для которого уже есть сигнал, то выполнение потока продолжится без задержки.

Существует два типа событий синхронизации: AutoResetEvent и ManualResetEvent. Отличие только одно: AutoResetEvent автоматически изменяется с состояния с сигналом на состояние без сигнала всегда при активации потока. В отличие от него, ManualResetEvent позволяет активировать состоянием с сигналом любое количество потоков, и вернется в состояние без сигнала только при вызове своего метода Reset.

Можно заставить потоки ожидать событий путем вызова одного из методов ожидания, например WaitOne, WaitAny или WaitAll. Метод WaitHandle..::.WaitOne()()() заставляет поток ждать сигнала одиночного события, метод WaitHandle..::.WaitAny()()() заставляет поток ждать сигнала одного или нескольких указанных событий, а метод WaitHandle..::.WaitAll()()() блокирует поток до получения сигнала от всех указанных событий. Событие выдает сигнал при вызове метода Set этого события.

В следующем примере поток создается и запускается функцией Main. Новый поток ждет события с помощью метода WaitOne. Поток приостанавливается до получения сигнала от события основным потоком, выполняющим функцию Main. После получения сигнала возвращается дополнительный поток. В этом случае, поскольку событие используется только для активации одного потока, можно использовать классы AutoResetEvent или ManualResetEvent.

using System;

using System.Threading;

class ThreadingExample

{

static AutoResetEvent autoEvent;

static void DoWork()

{

Console.WriteLine(" worker thread started, now waiting on event...");

autoEvent.WaitOne();

Console.WriteLine(" worker thread reactivated, now exiting...");

}

static void Main()

{

autoEvent = new AutoResetEvent(false);

Console.WriteLine("main thread starting worker thread...");

Thread t = new Thread(DoWork);

t.Start();

Console.WriteLine("main thread sleeping for 1 second...");

Thread.Sleep(1000);

Console.WriteLine("main thread signaling worker thread...");

autoEvent.Set();

}

}

Mutex Object

A mutex is similar to a monitor; it prevents the simultaneous execution of a block of code by more than one thread at a time. In fact, the name "mutex" is a shortened form of the term "mutually exclusive." Unlike monitors, however, a mutex can be used to synchronize threads across processes. A mutex is represented by the Mutex class.

When used for inter-process synchronization, a mutex is called a named mutex because it is to be used in another application, and therefore it cannot be shared by means of a global or static variable. It must be given a name so that both applications can access the same mutex object.

Although a mutex can be used for intra-process thread synchronization, using Monitor is generally preferred, because monitors were designed specifically for the .NET Framework and therefore make better use of resources. In contrast, the Mutex class is a wrapper to a Win32 construct. While it is more powerful than a monitor, a mutex requires interop transitions that are more computationally expensive than those required by the Monitor class.

------