Introduction
The monitor class have two static method Wait() and Pulse(). The purpose of Wait and Pulse is to provide a simple signaling mechanism: Wait blocks until it receives notification from another thread; Pulse provides that notification.
Wait must execute before Pulse in order for the signal to work. If Pulse executes first, its pulse is lost, and the late waiter must wait for a fresh pulse, or remain forever blocked. This differs from the behavior of an AutoResetEvent, where its Set method has a "latching" effect and so is effective if called before WaitOne.
One must specify a synchronizing object when calling Wait or Pulse. If two threads use the same object, then they are able to signal each other. The synchronizing object must be locked prior to calling Wait or Pulse.
When a thread is temporarily blocked from running, it calls Wait() This causes the thread to go to sleep and the lock for that object to be released, allowing another thread to use the object. At a later point, the sleeping thread is awakened when some other thread enters the same lock and calls Pulse() or PulseAll(). A call to Pulse() resumes the first thread in the queue of threads waiting for the lock. A call to PulseAll signals the release of the lock to all waiting threads.
Here are two commonly used forms of Wait():
public static bool
Wait(object waitObject)
public static bool Wait(object waitObject, int milliseconds)
public static bool Wait(object waitObject, int milliseconds)
The first form waits until notified. The second
form waits until notified or until the specified period of milliseconds has
expired. For both waitObject specifies the object upon which to wait.
Here are
the general forms for Pulse() and PulseAll():
public static void
Pulse(object waitObject)
public static void PulseAll(object waitObject)
public static void PulseAll(object waitObject)
Here,
waitObject is the object being released.
To
understand the need for and the application of Wait() and Pulse()
we create
following
program
using
System;
using
System.Threading;
namespace
WaitndPulesMethod
{
class PingPong
{
public void
ping(bool running)
{
lock (this)
{
if (!running)
{
//ball halts.
Monitor.Pulse(this); // notify any waiting threads
return;
}
Console.Write("Ping ");
Monitor.Pulse(this); // let pong() run
Monitor.Wait(this);
// wait for pong() to complete
}
}
public void
pong(bool running)
{
lock (this)
{
if (!running)
{
//ball halts.
Monitor.Pulse(this); // notify any waiting threads
return;
}
Console.WriteLine("Pong
");
Monitor.Pulse(this); // let ping() run
Monitor.Wait(this);
// wait for ping() to complete
}
}
}
class MyThread
{
public
Thread thread;
PingPong pingpongObject;
//construct a new thread.
public MyThread(string
name, PingPong pp)
{
thread = new Thread(new ThreadStart(this.run));
pingpongObject = pp;
thread.Name = name;
thread.Start();
}
//Begin execution of new thread.
void run()
{
if (thread.Name ==
"Ping")
{
for (int
i = 0; i < 5; i++)
pingpongObject.ping(true);
pingpongObject.ping(false);
}
else
{
for (int
i = 0; i < 5; i++)
pingpongObject.pong(true);
pingpongObject.pong(false);
}
}
}
class
BouncingBall
{
public static void Main()
{
PingPong pp =
new PingPong();
Console.WriteLine("The
Ball is dropped... \n");
MyThread mythread1 =
new MyThread("Ping",
pp);
MyThread mythread2 =
new MyThread("Pong",
pp);
mythread1.thread.Join();
mythread2.thread.Join();
Console.WriteLine("\nThe
Ball Stops Bouncing.");
Console.Read();
}
}
}