Synchronization Events and Wait Handles



Using a lock or monitor is useful for preventing the simultaneous execution of thread-sensitive blocks of code, but these constructs do not allow one thread to communicate an event to another. This requires synchronization events, which are objects that have one of two states, signaled and un-signaled, that can be used to activate and suspend threads. Threads can be suspended by being made to wait on a synchronization event that is unsignaled, and can be activated by changing the event state to signaled. If a thread attempts to wait on an event that is already signaled, then the thread continues to execute without delay.

There are two kinds of synchronization events: AutoResetEvent, and ManualResetEvent. They differ only in that AutoResetEvent changes from signaled to unsignaled automatically any time it activates a thread. Conversely, a ManualResetEvent allows any number of threads to be activated by its signaled state, and will only revert to an unsignaled state when its Reset method is called.

Threads can be made to wait on events by calling one of the wait methods, such as WaitOne, WaitAny, or WaitAll. WaitHandle..::.WaitOne()()() causes the thread to wait until a single event becomes signaled, WaitHandle..::.WaitAny()()() blocks a thread until one or more indicated events become signaled, and WaitHandle..::.WaitAll()()() blocks the thread until all of the indicated events become signaled. An event becomes signaled when its Set method is called.

In the following example, a thread is created and started by the Main function. The new thread waits on an event using the WaitOne method. The thread is suspended until the event becomes signaled by the primary thread that is executing the Main function. Once the event becomes signaled, the auxiliary thread returns. In this case, because the event is only used for one thread activation, either the AutoResetEvent or ManualResetEvent classes could be used.

 


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

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

Существует два типа событий синхронизации: 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.

 


 

 

ß------

 

Мьютексные объекты

Мьютекс аналогичен монитору, он не допускает одновременного выполнения блока кода более чем из одного потока. Название "мьютекс" – сокращенная форма слова "взаимоисключающий" ("mutually exclusive" на английском языке). Впрочем, в отличие от мониторов мьютексы можно использовать для синхронизации потоков по процессам. Мьютекс представляется классом Mutex.

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

Несмотря на то, что для синхронизации потоков внутри процесса можно использовать мьютекс, рекомендуется использовать Monitor, поскольку мониторы были созданы специально для .NET Framework и более эффективно используют ресурсы. Напротив, класс Mutex является оболочкой для структуры Win32. Мьютекс мощнее монитора, но для мьютекса требуются переходы взаимодействия, на которые затрачивается больше вычислительных ресурсов, чем на обработку класса Monitor.

 


Дата добавления: 2019-03-09; просмотров: 259; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!