To truely see if there's a simpler way to implement Monitor.Wait
, we'd ahve to investigate how it functions at a low level. The actual implementation is ultimately written in C and hidden from us but specifically for Monitor.Wait(object)
, we can trace the chain of calls in the following manner;
Monitor.Wait(o)
-- return Monitor.Wait(o, -1, false)
Monitor.Wait(o, -1, false)
-- Monitor.ObjWait(false [exitContext], -1 [millisecondsTimeout], o)
From here it's harder to see what's going on even in ILSpy. As per Tigran's link to the source of the Monitor
object, we're left with the following in the source;
/*========================================================================
** Waits for notification from the object (via a Pulse/PulseAll).
** timeout indicates how long to wait before the method returns.
** This method acquires the monitor waithandle for the object
** If this thread holds the monitor lock for the object, it releases it.
** On exit from the method, it obtains the monitor lock back.
** If exitContext is true then the synchronization domain for the context
** (if in a synchronized context) is exited before the wait and reacquired
**
** Exceptions: ArgumentNullException if object is null.
========================================================================*/
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern bool ObjWait(bool exitContext, int millisecondsTimeout, Object obj)
The description is left fairly self-explanitory into what's it's doing and in what sequence. However, the precise implementation by which it does so is wrapped from various private static extern
methods which contain the crucial code.
extern
specifies that the actual implementation lies in another assembly. It may be used with DllImport
when accessing unmanaged code (not the case here) or could be an extern alias. From here as per SO post asking about where to find the implementation of extern methods, you'd have to look at the C code itself which can be found in the Core CLR (credit Scott Chamberlain).
From here we're looking at the C method implementation for ObjWait()
which maps (line 1027) to ObjectNative::WaitTimeout
in the CLR;
FCIMPL3(FC_BOOL_RET, ObjectNative::WaitTimeout, CLR_BOOL exitContext, INT32 Timeout, Object* pThisUNSAFE)
{
FCALL_CONTRACT;
BOOL retVal = FALSE;
OBJECTREF pThis = (OBJECTREF) pThisUNSAFE;
HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
if (pThis == NULL)
COMPlusThrow(kNullReferenceException, W("NullReference_This"));
if ((Timeout < 0) && (Timeout != INFINITE_TIMEOUT))
COMPlusThrowArgumentOutOfRange(W("millisecondsTimeout"), W("ArgumentOutOfRange_NeedNonNegNum"));
retVal = pThis->Wait(Timeout, exitContext);
HELPER_METHOD_FRAME_END();
FC_RETURN_BOOL(retVal);
}
FCIMPLEND
Before getting into this, it's worth looking at this (also credit Scott Chamberlain), which states;
FCalls are identified in managed code as extern methods with the MethodImplOptions.InternalCall bit set.
This explains our link to ObjWait()
and ObjectNative::WaitTimeout
. So, breaking this down further, we can see basic null
and argument checks with appropriate exceptions raised if so. The crux is the call to pThis->Wait()
...at which point I can't quite trace further...yet.
From here we get to Object::Wait
(line 531), then going to SyncBlock::Wait
(line 3442). At this point we have most of the meat of the implementation and there's quite a bit to it.
Given all of the above and getting back to what you asked re a simpler implementation, I'd be wary of simplifying Monitor.Wait()
. There is a lot going on under the hood and it'd be very easy to make a mistake and have potential bugs in an alternative implementation.
EDIT
Serious shout out to Scott Chamberlain who did most of the investigation below ILSpy-level and delving/debugging the C code stack. Pretty much all investigatory work below ILSpy-level is his, I've merely compiled it here into an answer.