2010-08-19 166 views
7

我试图创建一个死锁的例子。我试了下面的代码。但不是造成僵局,而是像魅力一样。帮助我理解为什么它不会造成僵局。这段代码中的变化会导致死锁?多线程中的死锁

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 

namespace ReferenceTypes 
{ 
    class DeadLockExample 
    { 
     static int a; 
     static int b; 

     public static void Main(string[] args) 
     { 
      DeadLockExample.a = 20; 
      DeadLockExample.b = 30; 

      DeadLockExample d = new DeadLockExample(); 

      Thread tA = new Thread(new ThreadStart(d.MethodA)); 
      Thread tB = new Thread(new ThreadStart(d.MethodB)); 

      tA.Start(); 
      tB.Start(); 

      Console.ReadLine(); 
     } 

     private void MethodA() 
     { 
      lock (this) 
      { 
       Console.WriteLine(a); 
       Thread.Sleep(1000); 
       Console.WriteLine(b); 
      } 
     } 

     private void MethodB() 
     { 
      lock (this) 
      { 
       Console.WriteLine(b); 
       Thread.Sleep(1000); 
       Console.WriteLine(a); 
      } 
     } 
    } 
} 

回答

11

正如其他人所说的,两个锁以不同的顺序获取,以便每个人都在等待另一个。我也改变了睡眠长度之一,以确保发生死锁的可能性很高。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 

namespace ReferenceTypes 
{ 
    class DeadLockExample 
    { 
     static int a; 
     static int b; 

     static object lockedObjA = new object(); 
     static object lockedObjB = new object(); 

     public static void Main(string[] args) 
     { 
      DeadLockExample.a = 20; 
      DeadLockExample.b = 30; 

      DeadLockExample d = new DeadLockExample(); 

      Thread tA = new Thread(new ThreadStart(d.MethodA)); 
      Thread tB = new Thread(new ThreadStart(d.MethodB)); 

      tA.Start(); 
      tB.Start(); 

      Console.ReadLine(); 
     } 

     private void MethodA() 
     { 
      lock (DeadLockExample.lockedObjA) 
      { 
       Console.WriteLine(a); 
       Thread.Sleep(1200); 

       lock (DeadLockExample.lockedObjB) { 
        Console.WriteLine(b); 
       } 
      } 
     } 

     private void MethodB() 
     { 
      lock (DeadLockExample.lockedObjB) 
      { 
       Console.WriteLine(b); 
       Thread.Sleep(1000); 

       lock (DeadLockExample.lockedObjA) { 
        Console.WriteLine(a); 
       } 
      } 
     } 
    } 
} 
+0

除事实睡觉不保证* *发生死锁(仅同步可以做到这一点),这是一个伟大的答案:) – 2010-08-19 23:37:19

+0

我很欣赏的答案。谢谢。 – SaravananArumugam 2010-08-19 23:41:36

+1

这是典型的死锁例子。实际上,大多数死锁看起来与此完全相同,除了锁定采集在通过您甚至没有意识到正在运行的线程上的计时器事件的回调进行路由后,堆栈跟踪中通常至少有8次调用。 – 2010-08-19 23:45:13

3

2个锁,2个线程。

线程A取锁A,休眠,然后试图取锁B.线程B取锁B,休眠,然后尝试取锁A,等于死锁。

[线程A具有使得线程B花费锁B之前线程A试图获取它足够长睡]

0

维基百科 -

死锁是一种情况,其中,两个 或更多竞争行动每个 等待对方完成,因此 从来没有。

上面的代码不满足这个要求 - 线程A和线程B都在等待彼此完成。

1

这里有3种不同的方式可以导致死锁。这份清单并非详尽无遗。

从锁定部分调用阻塞方法。

在这个例子中,线程A获取一个锁,然后立即调用一个阻塞方法,同时线程B试图获取相同的锁,但是被挂起,因为线程A正在等待线程B在之前发信号通知事件它会释放锁。

public class Example 
{ 
    ManualResetEvent m_Event = new ManualResetEvent(false); 

    void ThreadA() 
    { 
    lock (this) 
    { 
     m_Event.WaitOne(); 
    } 
    } 

    void ThreadB() 
    { 
    lock (this) 
    { 
     m_Event.Set(); 
    } 
    } 
} 

获取两个无序锁定。

这里不需要解释,因为这是一个众所周知的问题。

public class Example 
{ 
    private object m_LockObjectA = new object(); 
    private object m_LockObjectB = new Object(); 

    void ThreadA() 
    { 
    lock (m_LockObjectA) lock (m_LockObjectB) { } 
    } 

    void ThreadB() 
    { 
    lock (m_LockObjectB) lock (m_LockObjectA) { } 
    } 
} 

无锁死锁。

这是我最喜欢的死锁插图,因为没有锁定或阻止方法。这个问题的微妙之处足以让那些熟悉线程的人感到困惑。这里的问题与缺乏记忆障碍有关。线程A等待线程B设置信号标志,同时线程B等待线程A重置它,直到线程没有看到其他人正在做出的更改,因为编译器,JIT和硬件可以自由优化以非直观的方式读取和写入标志。

public class Example 
{ 
    private bool m_Signal = false; 

    void ThreadA() 
    { 
    while (!m_Signal); 
    m_Signal = false; 
    } 

    void ThreadB() 
    { 
    m_Signal = true; 
    while (m_Signal); 
    } 
}