C# 避免死鎖,使用Monitor.TryEnter方法設定超時時間
阿新 • • 發佈:2021-06-18
1.在多工系統下,當一個或多個程序等待系統資源,而資源又被程序本身或其它程序佔用時,就形成了死鎖。總的來說,就是兩個執行緒,都需要獲取對方鎖佔有的鎖,才能夠接著往下執行,但是這兩個執行緒互不相讓,你等我先釋放,我也等你先釋放,但誰都不肯先放,就一直在這僵持住了。
2.死鎖演示:
1 static void Main(string[] args) 2 { 3 Task.Run(()=> Method1()); 4 Task.Run(() => Method2()); 5 Console.Read();6 } 7 static void Method1() 8 { 9 lock (obj1) 10 { 11 Console.WriteLine("開始執行方法一"); 12 Thread.Sleep(1000); 13 lock (obj2) 14 { 15 Console.WriteLine("方法一執行完畢"); 16 }17 } 18 } 19 static void Method2() 20 { 21 lock (obj2) 22 { 23 Console.WriteLine("開始執行方法二"); 24 Thread.Sleep(1000); 25 lock (obj1) 26 { 27 Console.WriteLine("方法二執行完畢"); 28 } 29 } 30 }
結果如下,這兩個方法永遠都不會執行完畢。
3.那麼,死鎖應該怎麼樣解決呢?
- 首先,應該儘量避免大量巢狀的鎖的使用,這也是預防為主,當然也有訊號量也可能會造成死鎖,這樣的話只能靠程式設計師自身注意去避免了。
- 如果需要使用巢狀鎖,可以使用鎖的超時機制來避免對資源的長時間佔用,演示如下:
1 private static readonly object obj1 = new object(); 2 private static readonly object obj2 = new object(); 3 static void Main(string[] args) 4 { 5 Task.Run(()=> Method1()); 6 Task.Run(() => Method2()); 7 Console.Read(); 8 } 9 static void Method1() 10 { 11 try 12 { 13 if (Monitor.TryEnter(obj1, 5000)) 14 { 15 Console.WriteLine("開始執行方法一"); 16 Thread.Sleep(1000); 17 bool locked = false; 18 try 19 { 20 Monitor.TryEnter(obj2, 5000, ref locked); 21 Console.WriteLine("方法一執行完畢"); 22 } 23 finally 24 { 25 if (locked) 26 { 27 Monitor.Exit(obj2); 28 } 29 } 30 } 31 } 32 finally 33 { 34 Monitor.Exit(obj1); 35 } 36 } 37 static void Method2() 38 { 39 try 40 { 41 if (Monitor.TryEnter(obj2, 5000)) 42 { 43 Console.WriteLine("開始執行方法二"); 44 Thread.Sleep(1000); 45 bool locked=false; 46 try 47 { 48 Monitor.TryEnter(obj1, 5000,ref locked); 49 Console.WriteLine("方法二執行完畢"); 50 } 51 finally 52 { 53 if (locked) 54 { 55 Monitor.Exit(obj1); 56 } 57 } 58 } 59 } 60 finally 61 { 62 Monitor.Exit(obj2); 63 } 64 }
這樣,即使在兩個執行緒都在互相等待資源的情況下,利用超時機制,依然能夠使他們放棄當前鎖,保證解決死鎖問題。