Introduction
In my previous article we have discussed the following Synchronization techniques:
- lock : Ensures just one thread
can access a resource, or section of code.
- Mutex
: Ensures just one thread can access a resource, or section of code. Can be
used to prevent multiple instances of an application from starting.
- Semaphore
:Ensures not more than a specified number of threads can access a resource,
or section of code.
In this article I will discribe a Must Inherit
type class,WaitHandle
.
WaitHandle
provides a class definition for three other classes, Mutex
, ManualResetEvent
and AutoResetEvent,
and provides means for your own objects to inherit synchronization
functionality. These objects allow threads to wait until classes derived from WaitHandle
are signaled. The
WaitHandle derived classes add functionality over Monitor in that threads can be programmed
to wait until multiple classes are signaled. Of course, along with more power
and flexibility comes more work and chance of problems.
AutoResetEvent
This acts like a turnstile (Moving Door) which
lets one at a time. When a thread hits WaitOne(), it waits till some other
thread calls set(). An
AutoResetEvent
gets reset automatically once the waiting thread observes the event is signalled
(set). Apart from this being convenient if you are reusing the event multiple
times, it has a practical application: if there are are multiple threads waiting
on an auto-reset event, only one of them will wake up when the event gets set.
As a waiting thread, if you observe that you have woken up because an auto-reset
event you were waiting on became signalled, then you can know that no other
thread waiting on that same event would have woken up.
The AutoResetEvent
class can be compared to the Monitor. Pulse
method. Imagine it as a tollbooth. Each car
has to pay to go through, the signal, and then the gate closes behind the car
when it es making the next car in line pay again. The AutoResetEvent
class is like this. It automatically goes back to unsignaled after being
signaled and a thread goes through, just like Monitor.
Pulse
. ManualResetEvent
can be described as a water hose, once open it lets everything through until you
close it yourself.
AutoResetEvent
allows threads to communicate with each other by signaling. Typically, this
communication concerns a resource to which threads need exclusive access. We
can control the initial state of an
AutoResetEvent
by ing a Boolean value to the constructor,true
if the initial state is signaled and
false
otherwise.
AutoResetEvent can also be used with the
static
I have put together a simple console
application to demonstrate this class.
using
System;
using
System.Threading;
namespace
AutoResetEventIN
{
class Process
{
AutoResetEvent auto;
Process()
{
auto = new
AutoResetEvent(false);
Thread t1 =
new Thread(new
ThreadStart(akshay));
Thread t2 =
new Thread(new
ThreadStart(csharpcorner));
t1.Start();
t2.Start();
auto.Set();
Thread.Sleep(1000);
auto.Set();
}
void akshay()
{
auto.WaitOne();
for (int
i = 0; i < 10; i++)
{
Thread.Sleep(500);
Console.WriteLine("Akshay
Teotia");
}
}
void csharpcorner()
{
auto.WaitOne();
for (int
i = 0; i < 10; i++)
{
Thread.Sleep(500);
Console.WriteLine("csharpcorner.com");
}
}
static void
Main(string[] args)
{
Process p =
new Process();
Console.Read();
}
}
}
Output
ManualResetEvent
ManualResetEvent allows
threads to communicate with each other by signaling. Typically, this
communication concerns a task which one thread must complete before other
threads can proceed. This is like a gate which lets more than one at a time.
When a thread hits WaitOne(), it waits till someother thread calls Set().
A
ManualResetEventis
useful if you want to wake up a bunch of threads with a single event. It's
useful for things like termination events where you don't want to reset the
event just because you observed it signalled. If the meaning of the event is
more like a flag, then you can observe the flag without changing its state back
to unsignalled.
When a thread begins an activity that must
complete before other threads proceed, it calls Reset to put
ManualResetEvent in the
non-signaled state. This thread can be thought of as controlling the
ManualResetEvent. Threads
that call WaitOne() on the
ManualResetEvent will block,
awaiting the signal. When the controlling thread completes the activity, it
calls
Set to signal that the waiting
threads can proceed. All waiting threads are released.
Once it has been signaled,
ManualResetEvent remains
signaled until it is manually reset. That is, calls to WaitOne()return
immediately. Like
AutoResetEvent
we can control the initial state of the
ManualResetEvent by ing a
Boolean value to the constructor, true if
the initial state is signaled and
false
otherwise.
ManualResetEvent can also be
used with the static WaitAll()
and
WaitAny() methods.
I have put together a simple console application
to demonstrate this class.
using
System;
using
System.Threading;
namespace
ManualResetEventIn
{
class MyThread
{
public
Thread th;
ManualResetEvent manualResetEvent;
public MyThread(string
name, ManualResetEvent e)
{
th = new
Thread(this.run);
th.Name = name;
manualResetEvent = e;
th.Start();
}
void run()
{
Console.WriteLine("Inside
thread " + th.Name);
for (int
i = 0; i < 10; i++)
{
Console.WriteLine(th.Name);
Thread.Sleep(50);
}
Console.WriteLine(th.Name +
" Done!");
manualResetEvent.Set();
}
}
class MainClass
{
public static
void Main()
{
ManualResetEvent evtObj =
new ManualResetEvent(false);
MyThread myThread =
new MyThread("Event
Thread 1", evtObj);
Console.WriteLine("Main
thread waiting for event.");
// Wait for signaled event.
evtObj.WaitOne();
Console.WriteLine("Main
thread received first event.");
evtObj.Reset();
myThread = new
MyThread("Event
Thread 2", evtObj);
// Wait for signaled event.
evtObj.WaitOne();
Console.WriteLine("Main
thread received second event.");
Console.Read();
}
}
}
Output