.NET监视器究竟何时进入内核模式

本文关键字:内核 模式 何时进 监视器 究竟 NET | 更新日期: 2023-09-27 18:00:02

我想编译一个列表,列出使Monitor进入内核模式或使用内核同步对象的所有可能条件。

同步块有一个引用内核对象的字段。因此,我推断lock有时会进入内核模式。

我发现:Lock(Monitor)在.NET中的内部实现

但是它有太多的问题需要回答,唯一有用的信息是OP通过简单地声明lock有时会进入内核模式来回答他自己的问题。此外,没有任何链接可以支持这个答案。

lock究竟什么时候进入内核模式(不是如果,也不是为什么——什么时候)?

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

来自里希特的书:;同步块包含内核对象的字段、拥有线程的ID、递归计数和等待线程计数"

.NET监视器究竟何时进入内核模式

通过查看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类进入内核模式。

当锁被严重争用时。

如果锁被轻度争用,则会有一个快速的CPU旋转锁来等待锁再次释放,但如果等待时间不够长,则线程会阻塞互斥锁,这涉及到内核模式调用以挂起线程和其他此类管理。

在执行spinwait步骤后,可能会存在额外的智能,例如在单核机器上跳过spinwait,因为只有在释放线程后才能释放有争议的锁。