Чтобы действительно увидеть, есть ли более простой способ реализации Monitor.Wait
, нам нужно исследовать, как он работает на низком уровне. Фактическая реализация в конечном итоге написана на C и скрыта от нас, но конкретно для Monitor.Wait(object)
мы можем проследить цепочку вызовов следующим образом;
Monitor.Wait(o)
-- return Monitor.Wait(o, -1, false)
Monitor.Wait(o, -1, false)
-- Monitor.ObjWait(false [exitContext], -1 [millisecondsTimeout], o)
Отсюда сложнее увидеть, что происходит даже в ILSpy. Согласно ссылке Тиграна на источник объекта Monitor
, у нас осталось следующее в источнике;
/*========================================================================
** 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)
Описание не требует пояснений относительно того, что он делает и в какой последовательности. Однако конкретная реализация, с помощью которой он это делает, основана на различных private static extern
методах, содержащих ключевой код.
extern
указывает, что фактическая реализация заключается в другая сборка. Он может использоваться с DllImport
при доступе к неуправляемому коду (здесь это не так) или может быть внешний псевдоним. Отсюда, согласно сообщению SO спрашивая о том, где найти реализацию внешних методов, вам нужно посмотреть на C сам код, который можно найти в Core CLR (кредит Скотта Чемберлена).
Отсюда мы рассмотрим реализацию метода C для ObjWait()
, который сопоставляет (строка 1027) с ObjectNative::WaitTimeout
в 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
Прежде чем углубляться в это, стоит просмотреть это. (также кредит Скотта Чемберлена), в котором говорится;
FCalls идентифицируются в управляемом коде как внешние методы с установленным битом MethodImplOptions.InternalCall.
Это объясняет нашу ссылку на ObjWait()
и ObjectNative::WaitTimeout
. Итак, разбивая это дальше, мы можем увидеть основные null
и проверки аргументов с соответствующими исключениями, возникающими, если это так. Суть в вызове pThis->Wait()
...в этот момент я не могу проследить дальше...пока.
Отсюда мы переходим к Object::Wait
(строка 531), затем перейдите к SyncBlock::Wait
(строка 3442 а>). На данный момент у нас есть большая часть мяса реализации, и это совсем немного.
Учитывая все вышесказанное и возвращаясь к тому, что вы просили о более простой реализации, я бы с осторожностью относился к упрощению Monitor.Wait()
. Под капотом происходит много, и было бы очень легко допустить ошибку и получить потенциальные ошибки в альтернативной реализации.
ИЗМЕНИТЬ
Серьезный привет Скотту Чемберлену, который провел большую часть расследования ниже уровня ILSpy и копался/отлаживал стек кода C . Практически вся исследовательская работа ниже уровня ILSpy принадлежит ему, я просто собрал ее здесь в ответ.
person
DiskJunky
schedule
17.10.2017