Skip to content

Why would Wait-Pulse-PulseAll need monitor lock


Till now, I did understand but didn’t remember the very situation, as I wasn’t the one creating thread pools and alike: all the core things were already there.
It’s a blessing to work for start-up.
You can think about

Monitor.Wait(toRetrieve); // will throw SynchronizationLockException

Now, after a look into docs, I see that one needs to hold the monitored object lock to avoid race conditions: a thread wakes up already holding a lock for an object it needs. The thread that did Pulse() acquired that lock and safely passed it to Wait()ing one.
Just watch out for deadlocks: it’s easy to wake up with one object lock, try to acquire another and die then…

lock(toRetrieve)
{
  Monitor.Wait(toRetrieve); // will throw SynchronizationLockException
}

As Doug Lea recommends in his excellent eternal “Concurrent Programming in Java“, just make it impossible. Lock only on a single object. If you really really need two locks, make them ordered: always acquire A then B.

If you do:

lock(a){
  // :
  lock (b)
  {
    //:
  }
  // or:
  b.SomethingThatLocks();
}

//then will you never ever do

lock(b)
{
  //:
  a.SomethingThatMightLock();
}

as calling other objects’ methods while holding a lock badly affects your karma.

For more in-detail look, read “EventWaitHandle and Monitors: how to pick one?” by Joe Duffy. He goes very deep down to system details.
He also did a nice brief overview of missed pulse problem – why do you always check wait condition in a loop:

while (toRetrieve.Count == 0)
{
  lock(toRetrieve)
  {
    Monitor.Wait(toRetrieve);
  }
}

Post a Comment

Your email is never published nor shared.