.NET 中的锁定(监视器)内部实现
为了掌握某些技术,您必须知道它是如何在较低的抽象级别上实现的。在多线程编程的情况下,了解同步原语会很有帮助。
这里问题来了,.NET中的Lock(Monitor)是如何实现的?
我对这些点感兴趣:
- 它使用操作系统对象吗?;
- 它需要用户模式还是内核模式?;
- 等待锁的线程的开销是多少?;
- 在什么情况下,等待锁的线程队列可能会被违反?
更新:
“如果多个线程争用锁,它们会在“就绪队列”中排队,并按照先到先得的原则授予锁。注意:Windows 和 CLR 行为中的细微差别意味着队列的公平性有时可能会被违反。” [C# 4.0 简而言之,Joseph Albahari] 这就是我在关于“违反队列”的最后一个问题中要问的内容。
For mastering of some technology you have to know how it's made at one abstraction level lower. In case of multithreading programming, it will be good to know about synchronization primitives.
Here is the question, how implemented Lock (Monitor) in .NET?
I'm intrested in such points:
- does it utilize OS objects?;
- does it require user mode or kernel mode?;
- what is overhead for threads that are waiting for lock?;
- in what cases threads queue that awaiting for the lock could be violated?.
Updated:
"If more than one thread contends the lock, they are queued on a “ready queue” and granted the lock on a first-come, first-served basis. Note: Nuances in the behavior of Windows and the CLR mean that the fairness of the queue can sometimes be violated." [C# 4.0 in a Nutshell, Joseph Albahari] So this is what I'm asking about in last question concerning 'violated queue'.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
维基百科文章也很好地描述了“监视器”是什么作为其基础技术,条件变量。
请注意,.NET 监视器是条件变量的正确实现;大多数已发布的 CV 的 Win32 实现都是不正确的,即使是在通常信誉良好的来源(例如 Dr. Dobbs)中找到的也是如此。这是因为 CV 无法轻松地从现有的 Win32 同步原语构建< /a>.
.NET CV 实现不是仅仅在 Win32 原语上构建浅层(且不正确)的包装器,而是利用它位于 .NET 平台上的事实,实现自己的等待队列等。
The Wikipedia article has a pretty good description of what a "Monitor" is, as well as its underlying technology, the Condition Variable.
Note that the .NET Monitor is a correct implementation of a condition variable; most published Win32 implementations of CVs are incorrect, even ones found in normally reputable sources such as Dr. Dobbs. This is because a CV cannot easily be built from the existing Win32 synchronization primitives.
Instead of just building a shallow (and incorrect) wrapper over the Win32 primitives, the .NET CV implementation takes advantage of the fact that it's on the .NET platform, implementing its own waiting queues, etc.
经过一番调查后,我找到了问题的答案。总的来说,CodeInChaos 和 Henk Holterman 是正确的,但这里有一些细节。
当线程开始与其他线程竞争锁时,它首先会执行自旋等待循环一段时间以尝试获取锁。所有这些操作都在用户模式中执行。然后,如果操作系统内核对象
Event
没有成功创建,线程将切换到内核模式并等待来自该Event
的信号。所以我的问题的答案是:
1. 在更好的情况下不会,但在更坏的情况下会(如果需要,
Event
对象会延迟创建);2. 一般来说,它工作在用户模式,但如果线程竞争锁的时间太长,线程可以切换到内核模式(通过 Win API 非托管函数调用);
3. 从用户模式切换到内核模式的开销(~1000 个 CPU 周期);
4. 微软声称它是像 FIFO 一样“诚实”的算法,但它并不保证这一点。 (例如,如果“等待队列”中的线程将被挂起,那么它将在恢复时移至队列末尾。)
After some investigations I've found out answers to my questions. In general CodeInChaos and Henk Holterman were right, but here is some details.
When thread start to contends for a lock with other threads firstly it it does spin-wait loop for a while trying to obtain lock. All this actions performs in user-mode. Then if no success OS kernel object
Event
creates, thread is switched to the kernel-mode and waits for signal from thisEvent
.So answer to my questions are:
1. In better case no, but in worse yes (
Event
object lazily creates if required);2. In general it works in user-mode but if threads compete for a lock too long, thread could be switched to kernel-mode (via Win API unmanaged function call);
3. Overhead for switch from user-mode to kernel-mode (~1000 CPU cycles);
4. Microsoft claim that it is "honest" algorithm like FIFO but it doesn't guarantee this. (E.g. If thread from 'waiting queue' will be suspended it moves to the end of queue when it would be resumed.)