Links

02.死锁

NSLog(@"之前 - %@", [NSThread currentThread]);
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"sync - %@", [NSThread currentThread]);
});
NSLog(@"之后 - %@", [NSThread currentThread]);
打印完第一句后,dispatch_sync 立即阻塞当前的主线程,然后把 Block 中的任务放到 main_queue 中, main_queue 中的任务会被取出来放到主线程中执行,但主线程这个时候已经被阻塞了,所以 Block 中的任务就不能完成,它不完成,dispatch_sync 就会一直阻塞主线程,这就是死锁现象。导致主线程一直卡死。 当然这里只是一个例子,死锁并不只会发生在主线程

一: 概述

所谓死锁,指的是两个或者两个以上的进程在执行的过程中,由于竞争资源或彼此通信造成的一种阻塞现象.
如果一个线程需要并行处理多个任务,那么就可以创建多个线程,但是线程多了,往往会产生冲突,当一个线程锁定了一个资源A,而又想去锁定资源B,而在另一个线程中,锁定了资源B,而又想去锁定资源A以完成自身的操作,两个线程都想得到对方的资源,而不愿意释放自己的资源,造成两个线程都在等待,而无法执行,此时就是死锁。
  • 死锁的规范定义
    • 集合中的每一个进程都在等待只能由本集合中的其他进程才能引发的事件,那么该组进程是死锁的。
注意 死锁与正常阻塞不一样 正常阻塞:事务请求被其他事务锁定的资源的锁时,发出请求的事务一直等到该锁被释放。默认情况下,除非设置了LOCK_TIMEOUT,否则SQL Server事务不会超时。因为发出请求的事务未执行任何操作来阻塞拥有锁的事务,所以该事务是被阻塞,而不是陷入了死锁。最后,拥有锁的事务将完成并释放锁,然后发出请求地事务将获取锁并继续执行。

二: 四个必要条件

  • 互斥(资源独占)
    • 一个资源一次只能被一个进程使用
  • 请求与保持(部分分配,占有申请)
    • 一个进程在申请新的资源的同时保持对原有资源的占有(只有这样才是动态申请,动态分配)
  • 不可剥夺(不可强占)
    • 资源申请者不能强行地从资源占有者手中夺取资源,资源只能由占有者自愿释放
  • 循环等待
    • 若干进程之间形成一种头尾相连的循环等待资源关

三: 产生原因

  • 系统资源不足,竞争不可剥夺资源引起的进程死锁
  • 竞争临时资源引起的死锁
  • 进程推进顺序不当引起死锁

四: 破坏死锁

需要破坏四个必要条件中的一个或几个
  • 互斥(不能改变)
    • 必然存在的,非共享设备所必须的
  • 破坏请求与保持
    • 对一个进程在请求资源时,它不能持有不可剥夺资源
  • 破坏不可剥夺
    • 对一个已经保持了某些不可剥夺资源的进程,提出新的资源请求而不能得到满足时,它必须释放已经保持的所有资源,待以后需要时再重新申请
  • 破坏循环
    • 对系统所有资源类型进行线性排列,并赋予不同序号。规定每个进程必须按序号递增的顺序请求资源。

五: 预防死锁

  • 每个进程(事务)将所有要使用的数据全部加锁,否则,就不能继续执行
  • 预先对数据对象规定一个封锁顺序,所有进程(事务)都按这个顺序加锁
  • 保证进程处于安全进程序列
  • 按同一顺序访问对象
  • 避免事务中的用户交互
  • 保持事务简短并在一个批处理中

参考