此代码是否会导致死锁?
问题描述:
using System;
using System.Threading;
namespace Threading
{
class Program
{
static void Main(string[] args)
{
Semaphore even = new Semaphore(1, 1);
Semaphore odd = new Semaphore(1, 1);
Thread evenThread = new Thread(() =>
{
for (int i = 1; i <= 100; i++)
{
even.WaitOne();
if(i % 2 == 0)
{
Console.WriteLine(i);
}
odd.Release();
}
});
Thread oddThread = new Thread(() =>
{
for(int i = 1; i <=100; i++)
{
odd.WaitOne();
if(i%2 != 0)
{
Console.WriteLine(i);
}
even.Release();
}
});
oddThread.Start();
evenThread.Start();
}
}
}
所以我写了这个代码,其中一个线程正在生成奇数并且其他正在生成偶数。此代码是否会导致死锁?
使用Semaphores
我确信他们在订单中打印数字并且完美地工作。
但我有一个特殊的情况,例如每个线程一直等到另一个线程释放它的信号。那么是否会出现这样一种情况,即两个线程都在等待,并且没有线程正在取得进展,并且存在死锁情况?
答
要发生死锁,两个或更多线程必须尝试获取两个或更多资源,但以不同的顺序执行。见例如Deadlock和Would you explain lock ordering?。
你的代码不会涉及每个线程多个锁†所以不具备死锁的能力。
它确实有能力引发异常。正如在this comment中指出的那样,从理论上讲,其中一个线程在其他线程之前足够远以至于它试图释放尚未被占用的信号量锁。例如,如果evenThread
在第一次调用even.WaitOne()
之前被预先占用(或者根本没有计划开始运行),但oddThread
可以运行,则oddThread
可以获取odd
信号量,处理if
语句,然后在evenThread
有机会获得该信号灯之前尝试呼叫even.Release()
。
这将导致被拨打给Release()
。
这对于单CPU系统来说可能性更大,这是目前很难找到的。 :)但是对于任何CPU配置,理论上它仍然是可能的。
†实际上,在设计中线程安全的Console.WriteLine()
调用中存在隐式锁定。但是从你的代码的角度来看,这是一个原子操作。你的代码不可能获得该锁,然后等待另一个锁。所以它与你的具体问题没有任何关系。
错误地初始化信号将很容易做到。请注意,你做错了,你创建了一个竞争条件,两个线程都会同时尝试WriteLine()。理想情况下,它会崩溃,因为你在一个没有等待但不会经常发生的信号量上调用Release。但不,没有僵局。 System.Threading.Barrier类可以做到这一点,当你不必重新创建它时总会更好。 –