To call Monitor.Wait(obj) or Monitor.Pulse(obj) it's necessary first to have entered the monitor, via lock(obj) or Monitor.Enter(obj). Why does the API require this?
Thread synchronization: Wait and Pulse demystified hints at something about conditional variables etc., but I don't see why I'd want that to always be used.
I mean if it's just that the implementation depends on the lock being acquired to do the work of Wait or Pulse, why not just implement that internally as a part of them? Why not decouple Wait and Pulse entirely from the other behaviour in Monitor and let the developer use these functions as they want? It seems like a pointless burden on the developer, but is there a good reason for it to be like this?
To be more specific, Monitor.Wait(obj) throws SynchronizationLockException if "Wait is not invoked from within a synchronized block of code". Monitor.Pulse(obj) throws SynchronizationLockException if "the calling thread does not own the lock for the specified object".