在.NET中锁定(监视器)内部实现
掌握一些技术,你必须知道它是如何在一个抽象层次上降低的。 在多线程编程的情况下,最好了解同步原语。
这里是一个问题,如何在.NET中实现Lock(Monitor)?
我对这样的观点很感兴趣:
- 它是否利用OS对象?
- 它需要用户模式还是内核模式?
- 等待锁定的线程的开销是多少?
- 在什么情况下可能会违反等待锁的线程队列?
更新:
“如果多个线程竞争锁定,它们将排队在”就绪队列“上,并以先到先得的方式授予锁定。注意:Windows和CLR行为中的细微差别意味着队列有时可能会被侵犯。“ [C#4.0简介,Joseph Albahari]这就是我在上一个关于“违反队列”问题中所提到的问题。
维基百科的文章对“监视器”是什么以及其底层技术“条件变量”有很好的描述。
请注意,.NET监视器是一个条件变量的正确实现; 大多数已发布的Win32实现的CV都是不正确的,甚至在正常声誉良好的资源(如Dobbs博士)中发现的。 这是因为CV不能从现有的Win32同步原语轻松构建。
.NET CV实现不是仅仅在Win32原语上构建一个简单的(而且不正确的)包装器,而是利用它在.NET平台上的实际优势,实现自己的等待队列等。
经过一些调查后,我发现了我的问题的答案。 一般CodeInChaos和Henk Holterman是对的,但这里有一些细节。
当线程开始首先与其他线程竞争锁定时,它会尝试获取锁定一段时间后进行自旋等待循环。 所有这些操作都以用户模式执行。 然后,如果OS内核对象Event
没有成功创建,则线程切换到内核模式并等待来自此Event
信号。
所以回答我的问题是:
1.在更好的情况下否,但更糟糕的是( Event
对象如果需要,懒洋洋地创建);
2.通常它在用户模式下工作,但是如果线程竞争锁定时间过长,线程可能会切换到内核模式(通过Win API非托管函数调用);
3.从用户模式切换到内核模式(〜1000个CPU周期)的开销;
4.微软宣称它是像FIFO这样的“诚实”算法,但并不能保证这一点。 (例如,如果来自'等待队列'的线程将被暂停,它将在恢复时移动到队列末尾。)