有人可以解释一下为什么我们需要嵌套锁定吗?
看看这个例子:
lock (locker)
lock (locker)
lock (locker)
{
...
}
有人可以解释一下(+示例将不胜感激)。
有人可以解释一下为什么我们需要嵌套锁定吗?
看看这个例子:
lock (locker)
lock (locker)
lock (locker)
{
...
}
有人可以解释一下(+示例将不胜感激)。
有人可以解释一下为什么我们需要嵌套锁定吗?
这只是一个问题,因为您可能对需要锁定的方法进行了嵌套(例如相互递归)调用。这些方法必须允许在资源已锁定但不能依赖它的情况下调用。所以嵌套锁定是允许的,而不是需要的。
您发布的代码(以及您参考的书)通过将其简化为内联场景来展示它是如何工作的。那不是“真正的”代码。
简单的规则是已经拥有锁的线程可以再次锁定它,并且退出的数量必须与进入的数量相匹配才能释放锁。
在某些情况下,在同一线程上嵌套锁的能力是否非常实用。
假设您有一个具有多个方法的类。假设您想要一个非常简单的锁定方案,如下所示:
class A
{
public void MethodOne()
{
using (locker)
{
...body...
}
}
public void MethodTwo()
{
using (locker)
{
...body...
}
}
}
现在,如果MethodOne
调用,如果监视器中没有可重入锁定功能MethodTwo
,您将在 开始时出现死锁。MethodTwo
线程只会通过locker
.
幸运的是,此示例仅适用于 .NET。储物柜“知道”哪个线程将其锁定以及锁定了多少次,它将(仅)让拥有的线程通过。该计数用于确保从其他等待线程的角度来看,解锁仅在退出时发生,MethodOne
而不是在退出时发生MethodTwo
。所以这是一个有用的嵌套锁定的例子。
另一方面,问题中提到的示例似乎来自这本书。作者想清楚地表明嵌套锁定在 .NET 中是可能的,自动的;但是他们的示例代码是人为的,不打算出现在任何人的代码中,除非试图了解锁定是如何在幕后工作的。
您的问题的直接答案是:您不需要嵌套锁定。但是,编译器允许这样做是为了使某些场景更易于编码。
在问题的示例代码中,内锁将始终成功 - 因为要获得内锁,您必须已经成功获得外锁。您的线程已经锁定locker
,因此内部锁定“自动”成功。
这从来都不是必需的,并且不提供额外的线程安全性。
但是,在 Jirka Hanika 的回答中发布的场景中,这种行为意味着一个线程安全成员可以被另一个线程安全成员调用,而不必担心死锁。
正如您所提到的,您根本不需要嵌套锁定。
但为了清楚起见,值得指出的是,有些锁可以嵌套。查看ReaderWriterLockSlim类,您可以在其中作为读锁输入,然后在该范围内,您可以将其升级为写锁。
编辑:正如 Royi Namir 指出的那样,调用嵌套函数每个都有自己的 lock,从概念上讲会产生上述场景,但是提出问题的方式,看起来 3 个锁在同一个范围内完成,一个接一个其他的意义不大。