繁体   English   中英

c#:如何实现Monitor.Wait?

[英]c#: How is Monitor.Wait Implemented?

如何在C#的system.threading.monitor类内部实现Monitor.Wait()方法?

https://www.codeproject.com/Articles/28785/Thread-synchronization-Wait-and-Pulse-demystified

从概念上讲,我正在设想这样的事情:

   class Monitor {
       public static Wait(object o) 
       {
           // Release Lock
           Monitor.Exit(o);

           // Spinlock until another Thread acquires Lock
           while(!Monitor.isEnter(o));

           // Wait to re-acquire lock
           Monitor.Enter(o);
       }
   }

这样准确吗? 还是我想念什么?

这是我考虑作为前面代码基础的典型监视器类示例。

using System.Threading;

readonly object o = new object();

// In Thread #1: (Where appropriate) 
lock(o) {
    Monitor.Wait(o);
}

//In Thread #2:  (Where appropriate) 
lock(o) {
    Monitor.Pulse(o);  
}

Lock(o)当然是内置的c#快捷方式,用于:

try {
    Monitor.Enter(o);
    {
        //Lock Block Here
    }
}
finally {
    Monitor.Exit(o);
}

要真正了解是否有实现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中也很难看到正在发生的事情。 根据Tigran到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一起使用(此处不是这种情况),也可以是extern别名 根据SO帖子,在这里询问在哪里可以找到extern方法的实现 ,您必须查看可以在Core CLR (信用Scott Chamberlain)中找到的C代码本身。

从这里开始,我们观察ObjWait()的C方法实现,该方法 (第1027行) 映射到CLR中的ObjectNative::WaitTimeout

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

进入此之前,它的价值看这个 (也归功于斯科特·张伯伦),其中规定;

FCall在托管代码中通过设置MethodImplOptions.InternalCall位设置为外部方法。

这解释了我们到ObjWait()ObjectNative::WaitTimeout 因此,进一步分解,我们可以看到基本的null和参数检查,并在适当的情况下引发了异常。 症结在于对pThis->Wait()的调用……在这一点上,我还无法进一步跟踪……。

从这里我们到达Object::Wait第531行 ),然后转到SyncBlock::Wait第3442行 )。 至此,我们已经掌握了实现的大部分内容,并且还有很多。

鉴于以上所有内容,然后返回您要求的是一个更简单的实现,我对简化Monitor.Wait()持谨慎Monitor.Wait() 幕后发生了很多事情,很容易犯一个错误,并且在替代实现中有潜在的错误。

编辑

认真地向斯科特·张伯伦大喊大叫, 斯科特·张伯伦在ILSpy级别以下进行了大部分调查,并对C代码堆栈进行了研究/调试。 ILSpy级别以下的几乎所有调查工作都是他的,这里我只是将其整理成一个答案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM