I have been coding with C# for a good little while, but this locking sequence does not make any sense to me. My understanding of locking is that once a lock is obtained with lock(object), the code has to exit the lock scope to unlock the object.
This brings me to the question at hand. I cut out the code below which happens to appear in an animation class in my code. The way the method works is that settings are passed to the method and modified and then passed to a another overloaded method. That other overloaded method will pass all the information to another thread to handle and actually animate the object in some way. When the animation completes, the other thread calls the OnComplete method. This actually all works perfectly, but I do not understand why!
The other thread is able to call OnComplete, obtain a lock on the object and signal to the original thread that it should continue. Should the code not freeze at this point since the object is held in a lock on another thread?
So this is not a need for help in fixing my code, it is a need for clarification on why it works. Any help in understanding is appreciated!
public void tween(string type, object to, JsDictionaryObject properties) {
// Settings class that has a delegate field OnComplete.
Tween.Settings settings = new Tween.Settings();
object wait_object = new object();
settings.OnComplete = () => {
// Why are we able to obtain a lock when the wait_object already has a lock below?
lock(wait_object) {
// Let the waiting thread know it is ok to continue now.
Monitor.Pulse(wait_object);
}
};
// Send settings to other thread and start the animation.
tween(type, null, to, settings);
// Obtain a lock to ensure that the wait object is in synchronous code.
lock(wait_object) {
// Wait here if the script tells us to. Time out with total duration time + one second to ensure that we actually DO progress.
Monitor.Wait(wait_object, settings.Duration + 1000);
}
}
As documented,
Monitor.Waitreleases the monitor it’s called with. So by the time you try to acquire the lock inOnComplete, there won’t be another thread holding the lock.When the monitor is pulsed (or the call times out) it reacquires it before returning.
From the docs: