I find System.Monitor very confusing, although I understand threading, locks, deadlocks, race conditions, dining philosophers and all that jazz. Normally I use a ManualResetEvent() to do inter-thread co-ordination, but I know that that's a heavyweight kernel object, and that System.Monitor (Enter/Pulse, etc.) is much more efficient. I've Googled and Googled but cannot find a sensible example.
I would be most grateful if the SO crew could explain this potentially wonderful construct to me :-)
Here's a very simple example; the call to Wait
releases the lock (allowing Worker
to obtain it) and adds the Main
thread to the lock-object's pending queue. Worker
then obtains the lock, and calls Pulse
: this moves the Main
thread into the lock-object's ready queue. When Worker
releases the lock, Main
can resume work.
Note that lock(obj) {...}
is just compiler-candy for Monitor.Enter
/Monitor.Exit
in a try/finally block.
[edit: I changed the sample to move lock(sync)
earlier, to avoid the (unlikely) risk of a missed Pulse]
static void Main()
{
object sync = new object();
lock (sync)
{
ThreadPool.QueueUserWorkItem(Worker, sync);
Console.WriteLine("Main sleeping");
// wait for the worker to tell us it is ready
Monitor.Wait(sync);
Console.WriteLine("Main woke up!");
}
Console.WriteLine("Press any key...");
Console.ReadKey();
}
static void Worker(object sync)
{
Console.WriteLine("Worker started; about to sleep");
Thread.Sleep(5000);
Console.WriteLine("Worker about pulse");
lock (sync)
{ // notify Main that we did something interesting
Monitor.Pulse(sync);
Console.WriteLine("Worker pulsed; about to release lock");
}
Console.WriteLine("Worker all done");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With