5

有人可以解释一下为什么我们需要嵌套锁定吗?

看看这个例子:

lock (locker)
  lock (locker)
    lock (locker)
      {
        ...
      }

在此处输入图像描述

有人可以解释一下(+示例将不胜感激)。

4

4 回答 4

13

有人可以解释一下为什么我们需要嵌套锁定吗?

这只是一个问题,因为您可能对需要锁定的方法进行了嵌套(例如相互递归)调用。这些方法必须允许在资源已锁定但不能依赖它的情况下调用。所以嵌套锁定是允许的,而不是需要的。

您发布的代码(以及您参考的书)通过将其简化为内联场景来展示它是如何工作的。那不是“真正的”代码。

简单的规则是已经拥有锁的线程可以再次锁定它,并且退出的数量必须与进入的数量相匹配才能释放锁。

于 2012-06-06T07:28:10.293 回答
5

在某些情况下,在同一线程上嵌套锁的能力是否非常实用。

假设您有一个具有多个方法的类。假设您想要一个非常简单的锁定方案,如下所示:

class A
{
    public void MethodOne()
    {
        using (locker)
        {
            ...body...
        }
    }

    public void MethodTwo()
    {
        using (locker)
        {
            ...body...
        }
    }
}

现在,如果MethodOne调用,如果监视器中没有可重入锁定功能MethodTwo,您将在 开始时出现死锁。MethodTwo线程只会通过locker.

幸运的是,此示例仅适用于 .NET。储物柜“知道”哪个线程将其锁定以及锁定了多少次,它将(仅)让拥有的线程通过。该计数用于确保从其他等待线程的角度来看,解锁仅在退出时发生,MethodOne而不是在退出时发生MethodTwo。所以这是一个有用的嵌套锁定的例子。

另一方面,问题中提到的示例似乎来自这本书。作者想清楚地表明嵌套锁定在 .NET 中是可能的,自动的;但是他们的示例代码是人为的,不打算出现在任何人的代码中,除非试图了解锁定是如何在幕后工作的。

于 2012-06-06T07:32:41.720 回答
2

您的问题的直接答案是:您不需要嵌套锁定。但是,编译器允许这样做是为了使某些场景更易于编码。

在问题的示例代码中,内锁将始终成功 - 因为要获得内锁,您必须已经成功获得外锁。您的线程已经锁定locker,因此内部锁定“自动”成功。

这从来都不是必需的,并且不提供额外的线程安全性。

但是,在 Jirka Hanika 的回答中发布的场景中,这种行为意味着一个线程安全成员可以被另一个线程安全成员调用,而不必担心死锁。

于 2012-06-06T08:27:49.600 回答
1

正如您所提到的,您根本不需要嵌套锁定。

但为了清楚起见,值得指出的是,有些锁可以嵌套。查看ReaderWriterLockSlim类,您可以在其中作为读锁输入,然后在该范围内,您可以将其升级为写锁。

编辑:正如 Royi Namir 指出的那样,调用嵌套函数每个都有自己的 lock,从概念上讲会产生上述场景,但是提出问题的方式,看起来 3 个锁在同一个范围内完成,一个接一个其他的意义不大。

于 2012-06-06T07:30:30.810 回答