2010-08-19 116 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); 
    } 
}