什么时候.NET Monitor完全进入内核模式?

Bop*_*Bop 8 .net c# multithreading .net-4.0 .net-4.5

我想编译一个列表,列出所有可能的条件,使Monitor转到内核模式/使用内核同步对象.

同步块有一个引用内核对象的字段,因此我推断lock它将在某个时候进入内核模式.

我发现了这个:.NET中的Lock(Monitor)内部实现

但它有太多的问题无法回答,唯一有用的信息是OP通过简单地说明lock将在某个时候进入内核模式来回答他自己的问题.此外,没有任何链接可以支持该答案.

我的问题是不同的 - 我想知道什么时候lock会进入内核模式(不是,不是为什么 - 当时).

如果与旧版本有任何不同,我更感兴趣的是了解.NET 4和4.5

编辑:从里希特书中:"同步块包含内核对象的字段,拥有线程的ID,递归计数和等待的线程计数."

Han*_*ant 19

通过查看SSCLI20发行版提供的CLR源代码,可以回答大多数这类问题.它现在已经相当陈旧,它是.NET 2.0复古版,但很多核心CLR功能并没有太大变化.

您要查看的源代码文件是clr/src/vm/syncblk.cpp.这里有三个类,AwareLock是负责获取锁的低级锁实现,SyncBlock是实现等待进入锁的线程队列的类,CLREvent是操作系统同步的包装器对象,你要问的那个.

这是C++代码,抽象级别非常高,这段代码与垃圾收集器进行了大量的交互,并且包含了大量的测试代码.所以我将简要介绍一下这个过程.

SyncBlock具有存储AwareLock实例的m_Monitor成员.SyncBlock :: Enter()直接调用AwareLock :: Enter().它首先尝试尽可能便宜地获得锁.首先检查线程是否已拥有锁,如果是这种情况,则只增加锁定计数.接下来使用FastInterlockCompareExchange(),这是一个与Interlocked.CompareExchange()非常相似的内部函数.如果锁没有争用,那么这很快就会成功,并且Monitor.Enter()会返回.如果没有,那么另一个线程已经拥有锁,使用AwareLock :: EnterEpilog.需要使用操作系统的线程调度程序,以便使用CLREvent.必要时动态创建它并调用其WaitOne()方法.这将涉及内核转换.

这足以回答你的问题:当争用锁并且线程必须等待时,Monitor类进入内核模式.

  • 感谢您的评论,该评论指出了CLR源中的相关部分.我对旋转部分特别感兴趣:它通常声称在进入内核之前首先进行旋转.我感兴趣的是它是如何旋转的(迭代次数,......).我看不到你所描述的代码路径中的旋转,但是,我在AwareLock :: TryEnter调用的AwareLock :: Contention中看到了旋转逻辑.现在看来,这只适用于使用超时的TryEnter,所以我猜在使用c#lock关键字时不会使用旋转.我对吗? (3认同)