C# 线程问题之死锁

47aeea44c66f0c018f878530c60c4c71.png

过多的锁定也会有麻烦。在死锁中,至少有两个线程被挂起,并等待对方解除锁定。由于两个线程都在等待对方,就出现了死锁,线程将无限等待下去。

c8f98a6be363c8c53e1e475532b991d6.png

为了说明死锁,下面实例化 StateObject 类型的两个对象,并把它们传递给SampleTask 类的构造函数。创建两个任务,其中一个任务运行 Deadlock1() 方法,另一个任务运行 Deadlock2() 方法:

var statel = new StateObject(); 
var state2 = new StateObject();
new Task(new SampleTask(statel, state2).Deadlock1).Start(); 
new Task(new SampleTask(statel, state2).Deadlock2).Start();

7b4f5636761a6df9cfff71cf8d0b8c09.png

Deadlock1() 和 Deadlock2() 方法现在改变两个对象 s1和 s2 的状态,所以生成了两个锁。Deadlock1() 方法先锁定 sl,接着锁定 s2。Deadlock2() 方法先锁定 s2,再锁定 sl。现在,有可能Deadlock1() 方法中 sl 的锁定会被解除。接着,出现一次线程切换,Deadlock2() 方法开始运行,并锁定 s2。第二个线程现在等待sl 锁定的解除。因为它需要等待,所以线程调度器再次调度第一个线程,但第一个线程在等待 s2 锁定的解除。这两个线程现在都在等待,只要锁定块没有结束,就不会解除锁定。这是一个典型的死锁。

public class SampleTask
{
  public SampleTask(StateObject sl, StateObject s2)
  {
    _sl = sl; 
    _s2 = s2;
  }
  private StateObject _sl;
  private StateObject _s2; 
  
  public void Deadlock1() 
  {
    int i = 0;
    while (true) 
    {
      lock (_s1) 
      {
        lock (_s2)
        {
          _s1.ChangeState(i); 
          _s2.ChangeState(i++);
          Console.WriteLine($"still running, {i}");
         }
       }
     }
  }
  public void Deadlock2()
  {
    int i = 0;
    while (ture)
    {
      lock (_s2) 
      {
        lock (_s1)
        {
          _s1.ChangeState(i); 
          _s2.ChangeState(i++);
          Console.WriteLine($"still running, {i}");
        }
      }
    }
  }
}

a8147c64e22c10dd838dd5fb6057771b.png

结果是,程序运行了许多次循环,不久就没有响应了。“仍在运行” 的消息仅写入控制台中几次。同样,死锁问题的发生频率也取决于系统配置,每次运行的结果都不同。

4120c6e98a3290a46e5de31bb4a25c03.png

死锁问题并不总是像这样那么明显。一个线程锁定了 s1,接着锁定 s2;另一个线程锁定了 s2,接着锁定 s1。在本例中只需要改变锁定顺序,这两个线程就会以相同的顺序进行锁定。但是,在较大的应用程序中,锁定可能隐藏在方法的深处。为了避免这个问题,可以在应用程序的体系架构中,从一开始就设计好锁定顺序,也可以为锁定定义超时时间。

技术群:添加小编微信并备注进群

小编微信:mm1552923   

公众号:dotNet编程大全      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值