死锁是怎样炼成的
Posted 西邮3G实验室
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了死锁是怎样炼成的相关的知识,希望对你有一定的参考价值。
1.死锁产生的原因
死锁是指多个进程或线程在运行过程中因争夺资源而造成的一种僵局。若无外力作用,它们都将无法向前推进。通俗来讲,死锁是多个进程或线程互相等待其它的进程或线程完成后才能继续执行,这样相互等待谁都无法完成
2.产生死锁的必要条件
1).互斥条件:进程对分配到的资源进行排它性使用,即在一段时间内,一个资源只能有一个进程使用。若此时有其它进程请求该资源,则只能等待,知道占有资源的进程使用完毕释放掉才可以访问。
2).请求和保持条件:进程已经保持了至少一个资源,又提出了新的资源请求,而新的资源此时被其他进程占用。这个时候请求的进程阻塞,但又不释放自己已经占有的资源。
3).不剥夺条件:进程已经获得的资源,其它进程不能进行抢占,只能由占有资源的进程使用完后自己释放掉。
4).环路等待条件:发生死锁时,存在进程正在等待其它进程占有的资源释放,而占有资源的进程又正在等待其它进程的资源,由此形成一个进程——资源的环形链,无法解除。
3.ios中的死锁
上边解释了为何会出现死锁,下面就看几个简单的例子看感受一下
案例一
分析:
1).dispatch_sync是同步线程
2).dispatch_get_main_queue()是运行在主线程中的主队列
3).任务1是同步的任务
4).任务2要等任务1完成之后才会运行
知道了以上几点就可以分析出来了:首先主线程运行到dispatch_sync,dispatch_sync是不会立刻返回的,它会堵塞线程,等block执行完之后才会返回。运行到dispatch_sync时,会把block里的任务加入到当前线程(即主线程)的任务队列的最后边,然后遵循FIFO来执行任务,此时任务1被加到了任务2的后面。
这时就有一个问题:任务2在等待dispatch_sync返回(即执行完block里的任务1)后才会执行,但是在任务队列里任务2可是在任务1的前面,这时就进入了互相等待的场面,即形成了死锁。
小总结:一般情况下,在当前线程使用dispatch_sync加任务到当前线程的任务队列里边,就会造成死锁。
案例二
-
这段代码会不会发生死锁呢?其实是不会的,上个案例提到过“在当前线程使用dispatch_sync加任务到当前线程的任务队列里边,就会造成死锁”,这里为什么不会发生死锁?看看打印出的日志就会有一点明白了
XiYouMobile:<NSThread: 0x608000071f40>{
number = 1, name = main
}
是在主线程打印的,并没有生成新的线程。 个人理解:串行队列加上同步执行是不会开启新线程的,block里面的任务添加到queue后,queue是由主线程执行的,故不会死锁。更清楚的说就是dispatch_sync这个任务是在主队列里面加到queue这个队列里的,而不是在当前对列添加任务到当前队列。总而言之就是:不在一个队列里面添加同步任务到这个队列,就不会产生案例一那种死锁(如有错误,麻烦告诉我真相!)。
案例三
分析
这段程序会造成死锁,先看看打印结果
XiYou:<NSThread: 0x600000267b40>{number = 3, name = (null)}
可以看出第二个输出永远不会执行。相比案例二,这次把dispatch_sync放到了dispatch_async里边,串行队列加上异步执行是会开启一个新线程的,在新开启的线程中调用dispatch_sync,把block里的任务添加到新开启的线程正在处理的queue中,类似于案例一那样,造成死锁。
小总结
因为队列是可以嵌套的,比如在A队列(串行)添加一个任务a,在a这个任务中向B队列(串行)添加任务b,在b这个任务中又向A队列添加任务,这间接满足了“在某一个串行队列中,同步的向这个队列添加任务”。但是每一次都没有直接向相同的队列中添加block。
所以判断是否发生死锁的最好方法就是看有没有在串行队列(当然也包括主队列)中向这个队列添加任务。又因为我们知道每个串行队列对应一个线程,所以只要不在某个线程中调用会阻塞这个线程的方法即可。
以上为本期内容。
微信:西邮3g实验室
微博:西邮移动应用开发实验室
西邮3G实验室
以上是关于死锁是怎样炼成的的主要内容,如果未能解决你的问题,请参考以下文章