C# 避免死锁,使用Monitor.TryEnter方法设定超时时间
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 }
这样,即使在两个线程都在互相等待资源的情况下,利用超时机制,依然能够使他们放弃当前锁,保证解决死锁问题。
本文来自博客园,作者:云辰,转载请注明原文链接:https://www.cnblogs.com/yunchen/p/14900265.html