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

sga*_*tto 1 c# deadlock locking task-parallel-library 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 ) );
    } );
}
Run Code Online (Sandbox Code Playgroud)

当然没有周围的锁,这个代码不会死锁.

编辑:

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

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
Run Code Online (Sandbox Code Playgroud)

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

Chr*_*Fin 5

这不起作用,因为你肯定在这里创建一个死锁:

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

您可以通过使用MaxDegreeOfParallelism = 1以下方式轻松验证:然后一切都在主线程中运行,并且级联锁不会死锁,因为它可以再次锁定,因为它是相同的线程.

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

注意:
如果您的系统没有90!CPU不能帮助提高性能MaxDegreeOfParallelism = 90- 建议保持这个数字小于或等于你的CPU /核心数(你可以通过它获得Environment.ProcessorCount).