为什么这段代码没有死锁?

时间:2012-05-17 17:53:34

标签: c# locking thread-safety deadlock

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

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

谢谢!

3 个答案:

答案 0 :(得分:8)

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

lock语句以及构建它的Monitor class在.NET中为reentrant


编辑以响应您的修改:

当您将调用添加到Build内部时,代码不会死锁 - 它会以递归方式调用自身。这不是阻止,而是永远运行(直到最终,你点击StackOverflowException),因为Build调用Clear再次调用Build它调用Clear等......

答案 1 :(得分:5)

lock的文档说:

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

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

这可以避免很多麻烦。

答案 2 :(得分:4)

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