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 崩溃)。

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

谢谢!

4

3 回答 3

8

在 C# 中,持有锁的线程可以进入同一个锁而不会阻塞。

lock语句以及构建它的Monitor 类在 .NET 中是可重入的。


编辑以响应您的编辑:

当您将调用添加到Build内部清除时,代码不会死锁 - 它会递归调用自身。它不是阻塞,而是永远运行(直到最终,您遇到StackOverflowException),因为Build调用Clear哪个调用Build再次调用哪个调用Clear等等......

于 2012-05-17T17:55:11.303 回答
5

的文档lock说:

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

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

这样可以省去很多麻烦。

于 2012-05-17T17:58:13.417 回答
4

我不会,因为 clear 是在已经应用锁的同一个线程中调用的。

于 2012-05-17T17:54:58.090 回答