2017-04-23 186 views
1
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我确信他们在订单中打印数字并且完美地工作。

但我有一个特殊的情况,例如每个线程一直等到另一个线程释放它的信号。那么是否会出现这样一种情况,即两个线程都在等待,并且没有线程正在取得进展,并且存在死锁情况?

+0

错误地初始化信号将很容易做到。请注意,你做错了,你创建了一个竞争条件,两个线程都会同时尝试WriteLine()。理想情况下,它会崩溃,因为你在一个没有等待但不会经常发生的信号量上调用Release。但不,没有僵局。 System.Threading.Barrier类可以做到这一点,当你不必重新创建它时总会更好。 –

回答

1

要发生死锁,两个或更多线程必须尝试获取两个或更多资源,但以不同的顺序执行。见例如DeadlockWould you explain lock ordering?

你的代码不会涉及每个线程多个锁所以不具备死锁的能力。

确实有能力引发异常。正如在this comment中指出的那样,从理论上讲,其中一个线程在其他线程之前足够远以至于它试图释放尚未被占用的信号量锁。例如,如果evenThread在第一次调用even.WaitOne()之前被预先占用(或者根本没有计划开始运行),但oddThread可以运行,则oddThread可以获取odd信号量,处理if语句,然后在evenThread有机会获得该信号灯之前尝试呼叫even.Release()

这将导致被拨打给Release()

这对于单CPU系统来说可能性更大,这是目前很难找到的。 :)但是对于任何CPU配置,理论上它仍然是可能的。


†实际上,在设计中线程安全的Console.WriteLine()调用中存在隐式锁定。但是从你的代码的角度来看,这是一个原子操作。你的代码不可能获得该锁,然后等待另一个锁。所以它与你的具体问题没有任何关系。