锁定aqcuired并进一步尝试锁定不阻塞:C#锁是否重入?

Kir*_*ril 20 .net c# concurrency multithreading deadlock

我已经编写了一个测试,我认为应该是一个有效的死锁案例.看来,一旦lock已经被一个类的实例获取,该实例就不再需要重新获取lock,即使我明确地尝试再次调用另一个方法lock.

这是班级:

internal class Tester
{
    private readonly object _sync = new object();

    public Tester() { }

    public void TestLock()
    {
        lock (_sync)
        {
            for (int i = 0; i < 10; i++)
            {
                Deadlock(i);
            }
        }

    }

    private void Deadlock(int i)
    {
        lock (_sync)
        {
            Trace.WriteLine(i + " no deadlock!");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

0没有死锁!
1没有死锁!
2没有死锁!
3没有死锁!
4没有死锁!
5没有死锁!
6没有死锁!
7没有死锁!
8没有死锁!
9没有死锁!

我本以为这会导致僵局......任何人都能对此有所了解吗?

Mar*_*ell 42

.NET中的锁是可重入的.仅阻止来自其他线程的收购.当同一个线程多次锁定同一个对象时,它只是增加一个计数器,并在释放时减少它.当计数器达到零时,锁实际上被释放以便从其他线程访问.


Han*_*ant 13

Monitor,Mutex和ReaderWriterLock类维护具有线程关联的锁.ReaderWriterLockSlim类允许您选择,它具有一个采用LockRecursionPolicy值的构造函数.使用LockRecursionPolicy.NoRecursion是一种优化,如果你的锁定非常精细,那么这是一个相当大的优化.

Semaphore类是一个没有任何线程关联的同步类.此代码可靠地死锁:

class Tester {
    private Semaphore sem = new Semaphore(1, 1);
    public void TestLock() {
        sem.WaitOne();
        for (int i = 0; i < 10; i++) Deadlock(i);
        sem.Release();
    }

    private void Deadlock(int i) {
        if (!sem.WaitOne(100)) Console.WriteLine("deadlock!");
        else {
            sem.Release();
            Console.WriteLine("No deadlock!");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

通常,线程仿射同步类需要两个线程和两个锁死锁.标准模式是一个线程获取锁A和B,另一个线程获取B和A.顺序很重要.

.NET编程中存在不太明显的死锁情况,这是由锁无法看到的,因为它们内置于.NET框架代码中.一个非常经典的是BackgroundWorker.您可以在Busy属性上旋转的UI线程中编写代码,等待BGW完成.当BGW具有RunWorkerCompleted事件处理程序时,它总是会死锁.它在UI线程空闲之前无法运行,在事件处理程序完成运行之前,BGW的Busy属性不会为false.