Tải bản đầy đủ - 0 (trang)
4-8. Synchronize the Execution of Multiple Threads Using an Event

4-8. Synchronize the Execution of Multiple Threads Using an Event

Tải bản đầy đủ - 0trang

CHAPTER 4 ■ THREADS, PROCESSES, AND SYNCHRONIZATION



Method



Description



SignalAndWait



A static method that causes the calling thread to signal a specified event object and

then wait on a specified event object. The signal and wait operations are carried out as

an atomic operation. You can also specify a timeout value. SignalAndWait is new to

.NET 2.0.



The key differences between the three event classes are how they transition from a signaled to an

unsignaled state, and their visibility. Both the AutoResetEvent and ManualResetEvent classes are local to

the process in which they are declared. To signal an AutoResetEvent class, call its Set method, which will

release only one thread that is waiting on the event. The AutoResetEvent class will then automatically

return to an unsignaled state. The code in recipe 4-4 demonstrates how to use an AutoResetEvent class.

The ManualResetEvent class must be manually switched back and forth between signaled and

unsignaled states using its Set and Reset methods. Calling Set on a ManualResetEvent class will set it to a

signaled state, releasing all threads that are waiting on the event. Only by calling Reset does the

ManualResetEvent class become unsignaled.

You can configure the EventWaitHandle class to operate in a manual or automatic reset mode,

making it possible to act like either the AutoResetEvent class or the ManualResetEvent class. When you

create the EventWaitHandle, you pass a value of the System.Threading.EventResetMode enumeration to

configure the mode in which the EventWaitHandle will function; the two possible values are AutoReset

and ManualReset. The unique benefit of the EventWaitHandle class is that it is not constrained to the local

process. When you create an EventWaitHandle class, you can associate a name with it that makes it

accessible to other processes, including unmanaged Win32 code. This allows you to synchronize the

activities of threads across process and application domain boundaries and synchronize access to

resources that are shared by multiple processes. To obtain a reference to an existing named

EventWaitHandle, call the static method EventWaitHandle.OpenExisting and specify the name of the

event.



The Code

The following example demonstrates how to use a named EventWaitHandle in manual mode that is

initially signaled. A thread is spawned that waits on the event and then displays a message to the

console—repeating the process every 2 seconds. When you press Enter, you toggle the event between a

signaled and a unsignaled state. This example uses the Thread.Join instance method, which we describe

in recipe 4-12.

using System;

using System.Threading;

namespace Apress.VisualCSharpRecipes.Chapter04

{

class Recipe04_08

{

// Boolean to signal that the second thread should terminate.

static bool terminate = false;

// A utility method for displaying useful trace information to the

// console along with details of the current thread.



179



www.it-ebooks.info



CHAPTER 4 ■ THREADS, PROCESSES, AND SYNCHRONIZATION



private static void TraceMsg(string msg)

{

Console.WriteLine("[{0,3}] - {1} : {2}",

Thread.CurrentThread.ManagedThreadId,

DateTime.Now.ToString("HH:mm:ss.ffff"), msg);

}

// Declare the method that will be executed on the separate thread.

// The method waits on the EventWaitHandle before displaying a message

// to the console and then waits two seconds and loops.

private static void DisplayMessage()

{

// Obtain a handle to the EventWaitHandle with the name "EventExample".

EventWaitHandle eventHandle =

EventWaitHandle.OpenExisting("EventExample");

TraceMsg("DisplayMessage Started.");

while (!terminate)

{

// Wait on the EventWaitHandle, time out after 2 seconds. WaitOne

// returns true if the event is signaled; otherwise, false. The

// first time through, the message will be displayed immediately

// because the EventWaitHandle was created in a signaled state.

if (eventHandle.WaitOne(2000, true))

{

TraceMsg("EventWaitHandle In Signaled State.");

}

else

{

TraceMsg("WaitOne Timed Out -- " +

"EventWaitHandle In Unsignaled State.");

}

Thread.Sleep(2000);

}

TraceMsg("Thread Terminating.");

}

public static void Main()

{

// Create a new EventWaitHandle with an initial signaled state, in

// manual mode, with the name "EventExample".

using (EventWaitHandle eventWaitHandle =

new EventWaitHandle(true, EventResetMode.ManualReset,

"EventExample"))

{



180



www.it-ebooks.info



CHAPTER 4 ■ THREADS, PROCESSES, AND SYNCHRONIZATION



// Create and start a new thread running the DisplayMesssage

// method.

TraceMsg("Starting DisplayMessageThread.");

Thread trd = new Thread(DisplayMessage);

trd.Start();

// Allow the EventWaitHandle to be toggled between a signaled and

// unsignaled state up to three times before ending.

for (int count = 0; count < 3; count++)

{

// Wait for Enter to be pressed.

Console.ReadLine();

//

//

//

if

{



You need to toggle the event. The only way to know the

current state is to wait on it with a 0 (zero) timeout

and test the result.

(eventWaitHandle.WaitOne(0, true))

TraceMsg("Switching Event To UnSignaled State.");

// Event is signaled, so unsignal it.

eventWaitHandle.Reset();



}

else

{

TraceMsg("Switching Event To Signaled State.");

// Event is unsignaled, so signal it.

eventWaitHandle.Set();

}

}

// Terminate the DisplayMessage thread, and wait for it to

// complete before disposing of the EventWaitHandle.

terminate = true;

eventWaitHandle.Set();

trd.Join(5000);

}

// Wait to continue.

Console.WriteLine(Environment.NewLine);

Console.WriteLine("Main method complete. Press Enter.");

Console.ReadLine();

}

}

}



181



www.it-ebooks.info



CHAPTER 4 ■ THREADS, PROCESSES, AND SYNCHRONIZATION



4-9. Synchronize the Execution of Multiple Threads Using a

Mutex

Problem

You need to coordinate the activities of multiple threads (possibly across process boundaries) to ensure

the efficient use of shared resources or to ensure that several threads are not updating the same shared

resource at the same time.



Solution

Use the System.Threading.Mutex class.



How It Works

The Mutex has a similar purpose to the Monitor discussed in recipe 4-7—it provides a means to ensure

that only a single thread has access to a shared resource or section of code at any given time. However,

unlike the Monitor, which is implemented fully within managed code, the Mutex is a wrapper around an

operating system synchronization object. This, and because Mutexes can be given names, means you can

use a Mutex to synchronize the activities of threads across process boundaries, even with threads running

in unmanaged Win32 code.

Like the EventWaitHandle, AutoResetEvent, and ManualResetEvent classes discussed in recipe 4-8, the

Mutex is derived from System.Threading.WaitHandle and enables thread synchronization in a similar

fashion. A Mutex is in either a signaled state or an unsignaled state. A thread acquires ownership of the

Mutex at construction or by using one of the methods listed in Table 4-1. If a thread has ownership of the

Mutex, the Mutex is unsignaled, meaning other threads will block if they try to acquire ownership.

Ownership of the Mutex is released by the owning thread calling the Mutex.ReleaseMutex method, which

signals the Mutex and allows another thread to acquire ownership. A thread may acquire ownership of a

Mutex any number of times without problems, but it must release the Mutex an equal number of times to

free it and make it available for another thread to acquire. If the thread with ownership of a Mutex

terminates normally, the Mutex becomes signaled, allowing another thread to acquire ownership.



The Code

The following example demonstrates how to use a named Mutex to limit access to a shared resource (the

console) to a single thread at any given time:

using System;

using System.Threading;

namespace Apress.VisualCSharpRecipes.Chapter04

{

class Recipe04_09

{



182



www.it-ebooks.info



CHAPTER 4 ■ THREADS, PROCESSES, AND SYNCHRONIZATION



// Boolean to signal that the second thread should terminate.

static bool terminate = false;

// A utility method for displaying useful trace information to the

// console along with details of the current thread.

private static void TraceMsg(string msg)

{

Console.WriteLine("[{0,3}] - {1} : {2}",

Thread.CurrentThread.ManagedThreadId,

DateTime.Now.ToString("HH:mm:ss.ffff"), msg);

}

// Declare the method that will be executed on the separate thread.

// In a loop the method waits to obtain a Mutex before displaying a

// message to the console and then waits 1 second before releasing the

// Mutex.

private static void DisplayMessage()

{

// Obtain a handle to the Mutex with the name "MutexExample".

// Do not attempt to take ownership immediately.

using (Mutex mutex = new Mutex(false, "MutexExample"))

{

TraceMsg("Thread started.");

while (!terminate)

{

// Wait on the Mutex.

mutex.WaitOne();

TraceMsg("Thread owns the Mutex.");

Thread.Sleep(1000);

TraceMsg("Thread releasing the Mutex.");

// Release the Mutex.

mutex.ReleaseMutex();

// Sleep a little to give another thread a good chance of

// acquiring the Mutex.

Thread.Sleep(100);

}

TraceMsg("Thread terminating.");

}

}



183



www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

4-8. Synchronize the Execution of Multiple Threads Using an Event

Tải bản đầy đủ ngay(0 tr)

×