与Lock.ForEach内部锁定和内部的死锁

时间:2014-09-15 11:11:14

标签: c# locking task-parallel-library deadlock parallel.foreach

你能解释为什么这段代码会死锁吗?

int[] testlist = new int[ ] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
lock ( testlock ) {
    Parallel.ForEach( testlist, new ParallelOptions( ) { MaxDegreeOfParallelism = 90 }, ( int i ) => {
        Console.WriteLine( "hi there before " + i + " " + Monitor.IsEntered( testlock ) );
        lock ( testlock ) {
            Console.WriteLine( "hi there inner " + i + " " + Monitor.IsEntered( testlock ) );
        }
        Console.WriteLine( "hi there after " + i + " " + Monitor.IsEntered( testlock ) );
    } );
}

当然没有周围的锁,这段代码不会死锁。

编辑:

感谢您的解释。典型的输出是:

hi there before 3 True
hi there inner 3 True
hi there after 3 True
hi there before 4 True
hi there inner 4 True
hi there after 4 True
hi there before 5 True
hi there inner 5 True
hi there after 5 True
hi there before 6 True
hi there inner 6 True
hi there after 6 True
hi there before 7 True
hi there inner 7 True
hi there after 7 True
hi there before 8 True
hi there inner 8 True
hi there after 8 True
hi there before 9 True
hi there inner 9 True
hi there after 9 True
hi there before 10 True
hi there inner 10 True
hi there after 10 True

实际上,典型的执行在我的机器上有两个线程:一个被阻塞等待锁定(" 1"一个)而另一个正在运行其他迭代(从3到10,注意输出的线性) )。 " 1"线程永远等待。现在很清楚,谢谢!

2 个答案:

答案 0 :(得分:5)

这不起作用,因为你肯定会在这里造成死锁:

lock(testlock)锁定testlock,然后Parallel.ForEach开始处理多个线程中的testlist。现在这些线程到达内部lock(testlock),但由于它仍然被其线程中的外部线程锁定,因此无法再将其锁定=>在处理完成之前,外部lock不会释放,但是在外部lock发布后,处理无法完成 - >死锁...

您可以使用MaxDegreeOfParallelism = 1轻松验证这一点:然后一切都在主线程中运行,并且级联锁没有死锁,因为它可以再次锁定,因为它是相同的线程。

你想做什么 - 如果你解释一下,我们可以帮忙吗?

注意:
如果您的系统没有 90! CPU,它无法帮助提高性能[{1}} - 建议将该数字保持小于或等于您的CPU /核心数量(您可以获得通过Environment.ProcessorCount)。

答案 1 :(得分:3)

在开始testLock(第一次锁定)之前,您已锁定Parallel.ForEach。在Parallel.ForEach中,您可以锁定同一个对象。 ForEach在第一次锁定之外的某个点使用不同的线程。该线程将等待锁定可用,但它永远不可用,因为在ForEach完成之前,第一个锁定不会被释放。

由于ForEach在所有线程完成之前不会退出,因此最终会死锁。