2013-02-17 42 views
8

我想编译一个所有可能的条件列表,使Monitor进入内核模式/使用内核同步对象。什么时候.NET Monitor进入内核模式?

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

我发现这一点:Lock (Monitor) internal implementation in .NET

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

我的问题是不同的 - 我想知道何时lock将进入内核模式(不是如果不是为什么 - 何时)。

我更感兴趣地听到有关.NET 4和4.5是否存在与旧版本任何区别

编辑:从里氏书:“一个同步块包含一个内核对象领域,拥有线程ID,递归计数和等待线程数。“

回答

19

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

+0

非常感谢。特别是对于SSCLI - 我不知道这是公开的。 – 2013-02-17 17:11:13

+3

感谢您对CLR资源中的相关部分的评论。我特别感兴趣的是纺纱部分:它通常声称在进入内核之前首先监测纺纱。我感兴趣的是它如何旋转(迭代次数,...)。我看不到你已经描述的代码路径中的旋转,但是,我看到AwareLock :: Contention由AwareLock :: TryEnter调用的旋转逻辑。现在看来,这只适用于使用超时时的TryEnter,所以我猜在使用c#lock关键字时不会使用旋转。我对吗? – 2013-12-10 17:42:02

1

经过spinwait步骤。

可能存在其他智能,例如在单核机器上跳过spinwait,因为有争议的锁只能在释放线程后释放。

+0

安德鲁我需要有平面视图中的所有步骤,看看这是如何回答这个问题。你的答案就像 - 当人们在遭受雷击时死亡 - 当他们死亡时。 – 2013-02-17 16:29:09

+0

@BoppityBop:去让自己的飞机和简易机场,然后我们讨论这个点 – 2013-02-17 16:49:11

+0

雅。如果你想要更精确的东西,“5点04分02.008”怎么样?严重的是,绝对答案是无用的,相对答案也会有所不同。唯一剩下的就是一个合乎逻辑的答案。在上一步完成之后,您的问题缺乏一点。你为什么在乎?如果你提供了,我们可能会提供更有用的答案。 – 2013-02-17 17:13:09

2

当锁严重争夺。

如果锁轻微竞争,会有一个快速的CPU自旋锁等待锁再次释放,但是如果这样没有足够长的时间让锁自由释放,则线程将阻止等待互斥体,其中涉及内核模式调用以暂停线程和其他此类管理。

相关问题