【发布时间】:2023-03-03 12:26:01
【问题描述】:
你能解释一下为什么这段代码会死锁吗?
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”线程永远等待。现在清楚了,谢谢!
【问题讨论】:
-
假设主线程是thread1。 Thread1 锁定
testLock。由Parallel.ForEach生成的所有其他线程(与线程1 不同的线程!)也希望锁定testLock,但它仍被线程1 锁定。 Thread1 等待所有Parallel-threads 完成=死锁。 -
如果
Parallel决定在当前主线程(调用Parallel.ForEach的那个线程)上运行所有迭代,那么这段代码永远可以工作的唯一方法。据我所知,如果你只有一个核心,它可能会选择这样做......在所有其他情况下:是的,它会死锁......因为你已经写了一个死锁。
标签: c# locking task-parallel-library deadlock parallel.foreach