为什么这段代码不会死锁?

5
我期望以下代码发生死锁,当Clear 尝试对已被Build 锁定的同一对象进行锁定时:
void Main()
{
    (new SiteMap()).Build();
}

class SiteMap
{
    private readonly object _lock = new object();

    public void Build()
    {
        lock (_lock)
        {
            Clear();

            Console.WriteLine("Build");
        }
    }

    public void Clear()
    {
        lock (_lock)
        {
            Console.WriteLine("Clear");
        }
    }
}

输出:

清除

构建

编辑 1

谢谢大家的回答。

如果我在 Clear 的锁内添加对 Build 的调用(保持其余代码不变):

public void Clear()
{
    lock (_lock)
    {
        Build();

        Console.WriteLine("Clear");
    }
}

死锁发生了(至少我认为是这样,因为LINQ Pad崩溃了)。

根据您的回答,这不应该发生,因为它仍然是同一个线程。

谢谢!


1
请查看http://www.albahari.com/threading/part2.aspx,找到“嵌套锁定”一节。 - Robert Harvey
3个回答

8
在C#中,一个持有锁的线程可以无阻塞地再次进入相同的锁。
在.NET中,lock语句以及其构建的Monitor类都是可重入的。(译者注:即允许同一线程多次获取同一把锁)

针对您的编辑做出回应:

当您在clear函数中添加对Build的调用时,代码不会死锁 - 它会递归地调用自身。它不是阻塞,而是一直运行(直到最终出现StackOverflowException异常),因为Build调用ClearClear再次调用BuildBuild又再次调用Clear,以此类推......


关于我的编辑,我真的不知道为什么我没有看到那个。感谢两个答案! - stacker

5

lock 的文档说明如下:

如果另一个线程试图进入锁定的代码,则它将等待(阻塞),直到对象被释放为止。

关键字是“另一个”。一个线程不会阻塞自己,只会阻塞其他线程。如果另一个线程拥有该锁,则 lock 会阻塞。

这样可以避免很多麻烦。


4

我不能这样做,因为“clear”是在已经应用锁的同一线程内调用的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接