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