C#中的重入锁
Posted
技术标签:
【中文标题】C#中的重入锁【英文标题】:Re-entrant locks in C# 【发布时间】:2010-09-28 08:39:24 【问题描述】:以下代码会导致在 .NET 上使用 C# 导致死锁吗?
class MyClass
private object lockObj = new object();
public void Foo()
lock(lockObj)
Bar();
public void Bar()
lock(lockObj)
// Do something
【问题讨论】:
我们是否可以考虑改变这个问题的标题——也许是像最近关闭的Why do nested locks not cause a deadlock? 这样的标题似乎几乎是为了防止人们发现它。 其实我是根据搜索词“reentrant”找到的,它回答了我的问题。如果这是一个 dup 问题,那就是另一个问题了...... 我同意@JeffSternal 的评论这个问题假设搜索问题的人已经熟悉“重入”锁。另一个我认为有一个很好的标题的重复问题:***.com/questions/3687505/… 【参考方案1】:不,只要您锁定同一个对象。递归代码实际上已经拥有锁,因此可以不受阻碍地继续运行。
lock(object) ...
是使用 Monitor 类的简写。由于Marc points out、Monitor
允许re-entrancy,因此重复尝试锁定当前线程已锁定的对象 将正常工作。
如果您开始锁定不同的 对象,那就是您必须小心的时候。特别注意:
始终以相同的顺序在给定数量的对象上获取锁。 始终按照逆向顺序释放锁。如果你违反了这些规则中的任何一个,你几乎肯定会在某个时候遇到死锁问题。
这是一个描述 .NET 中线程同步的好网页:http://dotnetdebug.net/2005/07/20/monitor-class-avoiding-deadlocks/
此外,一次锁定尽可能少的对象。考虑在可能的情况下应用coarse-grained locks。这个想法是,如果您可以编写代码以便有一个对象图并且您可以在该对象图的根上获取锁,那么就这样做。这意味着您在该根对象上拥有一个锁,因此不必担心获取/释放锁的顺序。
(进一步说明,您的示例在技术上不是递归的。要使其递归,Bar()
必须调用自身,通常作为迭代的一部分。)
【讨论】:
特别是在不同的序列中。 重新递归;确实;为了 Guy 的利益,这个词是可重入的 感谢您对术语的澄清 - 我已经编辑并更正了这个问题。 这个问题似乎引起了相当多的关注,所以我用我第一次写它以来提出的其他一些笔记更新了我的答案。 实际上,我认为您释放锁的顺序并不重要。您选择它们的顺序肯定可以,但是只要释放锁不以任何条件为条件(您可以随时释放),只要释放您获得的所有锁就应该没问题。 【参考方案2】:好吧,Monitor
允许重新进入,所以你不能让自己陷入僵局……所以不:不应该这样做
【讨论】:
【参考方案3】:如果一个线程已经持有一个锁,那么它不会阻塞自己。 .Net 框架确保了这一点。您只需要确保两个线程不会尝试通过任何代码路径不按顺序获取相同的两个锁。
同一个线程可以多次获取同一个锁,但您必须确保释放锁的次数与获取锁的次数相同。当然,只要您使用“lock”关键字来完成此操作,它就会自动发生。
【讨论】:
请注意,这适用于监视器,但不一定适用于其他类型的锁。 (当然,不想暗示你不知道——只是这是一个重要的区别:) 这很好。我实际上打算将“锁定”更改为“监控”,但后来我分心了。和懒惰。 Windows 互斥体内核对象的行为也是如此,所以我想,足够接近了!【参考方案4】:不,此代码不会有死锁。 如果您真的想创建死锁,最简单的一个需要至少 2 个资源。 考虑狗和骨头的场景。 1. 一只狗可以完全控制一根骨头,因此任何其他狗都必须等待。 2. 最少需要2只2块骨头的狗,分别锁定自己的骨头并寻找其他骨头时造成僵局。
.. 以此类推 n 狗和 m 骨头,并导致更复杂的死锁。
【讨论】:
以上是关于C#中的重入锁的主要内容,如果未能解决你的问题,请参考以下文章