9

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

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

我发现了这个:Lock (Monitor) internal implementation in .NET

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

究竟什么时候会lock进入内核模式(不是如果而不是为什么 - 什么时候)?

如果与旧版本有任何区别,我更有兴趣了解 .NET 4 和 4.5。

来自 Richter 的书:“同步块包含内核对象的字段、拥有线程的 ID、递归计数和等待线程计数。”

4

3 回答 3

20

大多数这类问题都可以通过查看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 类进入内核模式。

于 2013-02-17T17:09:31.747 回答
4

当锁被严重争用时。

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

于 2013-02-17T16:37:30.160 回答
0

在其 spinwait 步骤之后,可能存在额外的智能,例如在单核机器上跳过 spinwait,因为竞争锁只能在释放线程后释放。

于 2013-02-17T15:27:50.227 回答