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         }

结果如下,这两个方法永远都不会执行完毕。

C# 避免死锁,使用Monitor.TryEnter方法设定超时时间

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         }

    C# 避免死锁,使用Monitor.TryEnter方法设定超时时间

     这样,即使在两个线程都在互相等待资源的情况下,利用超时机制,依然能够使他们放弃当前锁,保证解决死锁问题。