[C#.NET][Thread] 執行緒的互鎖與死鎖
所謂死結是由兩條執行緒(或者更多),因互相等待而造成了死結。
互鎖是表示兩條執行緒中,一次只有一條執行在工作,另一條在等待,這如果沒弄好很容易弄巧成拙變成死結。
public static void MethodA() { lock (_LockA) { //TODO... lock (_LockB) { //TODO... } } }
public static void MethodB() { lock (_LockB) { //TODO... lock (_LockA) { //TODO... } } }
上面是一個死結寫法,MethodA鎖了_LockA,MethodB鎖了_LockB;MethodA裡的方法在等_LockB釋放,MethodB裡的方法在等_LockA釋放
接下來就來實作一下怎麼打死結
static object _LockA = new object(); static object _LockB = new object(); static void Main(string[] args) { Thread threadA = new Thread(new ThreadStart(MethodA)); Thread threadB = new Thread(new ThreadStart(MethodB)); threadB.Start(); threadA.Start(); //主執行緒等待其他執行緒完成工作 threadB.Join(); threadA.Join(); Console.WriteLine("Main Thread Exit"); Console.ReadKey(); } public static void MethodA() { Thread t = Thread.CurrentThread; lock (_LockA) { Console.WriteLine("Thread[{0}]:Enter MethodA, _LockA be Locked ,State:{1}", t.ManagedThreadId, t.ThreadState); lock (_LockB) { Console.WriteLine("Thread[{0}]:Enter MethodA ,_LockB be Locked ,State:{1}", t.ManagedThreadId, t.ThreadState); } Console.WriteLine("Thread[{0}]:Leave MethodA ,State:{1}", t.ManagedThreadId, t.ThreadState); } } public static void MethodB() { Thread t = Thread.CurrentThread; lock (_LockB) { Console.WriteLine("Thread[{0}]:Enter MethodB, _LockB be Locked ,State:{1}", t.ManagedThreadId, t.ThreadState); lock (_LockA) { Console.WriteLine("Thread[{0}]:Enter MethodB, _LockA be Locked ,State:{1}", t.ManagedThreadId, t.ThreadState); } } Console.WriteLine("Thread[{0}]:Leave MethodB ,State:{1}", t.ManagedThreadId, t.ThreadState); }
執行結果就是兩個互相等待…程式不會結束
解決死結的方法很簡單,只要大家都用一樣的鎖定順序就不會變死結了,在原本MethodB裡的鎖定順序變成跟MethodA一樣就好了
public static void MethodB() { Thread t = Thread.CurrentThread; lock (_LockA) { Console.WriteLine("Thread[{0}]:Enter MethodB, _LockA be Locked ,State:{1}", t.ManagedThreadId, t.ThreadState); lock (_LockB) { Console.WriteLine("Thread[{0}]:Enter MethodB, _LockB be Locked ,State:{1}", t.ManagedThreadId, t.ThreadState); } } Console.WriteLine("Thread[{0}]:Leave MethodB ,State:{1}", t.ManagedThreadId, t.ThreadState); }
同樣的寫法若換成Monitor類別,下面的寫法也是死結,要解決很簡單,記住,鎖定順序都要一樣就不會有死結
public static void MethodC() { Monitor.Enter(_LockC); try { try { Monitor.Enter(_LockD); } catch (Exception) { } finally { Monitor.Exit(_LockD); } } catch (Exception) { } finally { Monitor.Exit(_LockC); } } public static void MethodD() { Monitor.Enter(_LockD); try { try { Monitor.Enter(_LockC); } catch (Exception) { } finally { Monitor.Exit(_LockC); } } catch (Exception e) { } finally { Monitor.Exit(_LockD); } }
非死結的完整程式碼
public static void MethodC() { Thread t = Thread.CurrentThread; Monitor.Enter(_LockC); try { Console.WriteLine("Thread[{0}]:Enter MethodC, _LockC be Locked ,State:{1}", t.ManagedThreadId, t.ThreadState); try { Monitor.Enter(_LockD); Console.WriteLine("Thread[{0}]:Enter MethodC, _LockD be Locked ,State:{1}", t.ManagedThreadId, t.ThreadState); } catch (Exception) { } finally { Monitor.Exit(_LockD); } } catch (Exception) { } finally { Monitor.Exit(_LockC); Console.WriteLine("Thread[{0}]:Leave MethodC ,State:{1}", t.ManagedThreadId, t.ThreadState); } } public static void MethodD() { Thread t = Thread.CurrentThread; Monitor.Enter(_LockC); try { Console.WriteLine("Thread[{0}]:Enter MethodD, _LockD be Locked ,State:{1}", t.ManagedThreadId, t.ThreadState); try { Monitor.Enter(_LockD); Console.WriteLine("Thread[{0}]:Enter MethodD, _LockC be Locked ,State:{1}", t.ManagedThreadId, t.ThreadState); } catch (Exception) { } finally { Monitor.Exit(_LockD); } } catch (Exception) { } finally { Monitor.Exit(_LockC); Console.WriteLine("Thread[{0}]:Leave MethodD ,State:{1}", t.ManagedThreadId, t.ThreadState); } }
本文转自http://www.dotblogs.com.tw/yc421206/archive/2011/01/18/20878.aspx
浙公网安备 33010602011771号