GCD中Dispatch产生死锁的原因--不忽悠

为啥要写这篇文章呢,还是因为大部分文章介绍为啥产生死锁时基本都是一个模子,让人看着那个难受呀,根本就是忽悠,压根就说不通。

我呢,说的不一定对,只是个人理解,如有错误,虚心接受批评教育~    

我在这也只是介绍一下为啥产生那个常见的死锁,对于GCD中线程、队列、信号量、栅栏详细的介绍已经有很多优秀的文章介绍的很清楚了。

最经典的死锁案例无非就是它了


好多文章说,是任务2等待任务1,任务1等待任务2,这TM纯属放屁 ~ 你把"打印任务2"删掉,它同样会产生死锁

介入正题,咱们得知道几个基本的知识点

队列:队列是用来存放任务的,将要做的事放到队列里。可以把队列想象成一个容器,容器里放着土豆(任务)

1、串行队列--每次只能执行一个任务,并且必须等待前一个执行任务完成。串行队列容器就是一根管,一只手进去拿土豆时,另一只手伸不进去,所以只能拿出一个土豆来以后,才能接着拿另一个。

2、并发队列--一次可以并发执行多个任务,不必等待执行中的任务完成。并行队列是一个盆,一只手进去拿土豆,就算个还没拿出来另一只手也可以进去拿。

3、dispatch_sync --同步派发任务:对队列里等待的任务,处理完一个以后(处理完后,dispatch_sync中block里的方法才会return结束,比如拿起土豆,并且放到地上以后,才算结束),才会再去取另一个任务(土豆)、没有开辟新线程的能力(只有一只手可用,另一只手,受伤中 ~),并且会阻塞当前线程。比如下图,必须要"第三步"执行完以后,这个任务才算完成。


4、dispatch_async--异步派发任务,队列里的任务可以在一个没执行完的情况下(任务一开始就会return结束,比如拿土豆,只要我碰到土豆,就算这个任务处理完了,不管我有没有拿出来),接着开始执行另一个(有好多只手,一只手碰到土豆以后,另一只手在条件允许的情况下,可以继续另一个土豆)、有开辟新线程的能力(也就是有多只手同时工作的能力),不会阻塞当前线程。比如下图,"第一步"开始执行了,就有可能接着执行"第四步",也有可能是"第四步"先执行(第二只手神速 ~)


明白了这几个概念以后,咱们就说为啥会产生死锁。


继续把上面的图拿过来,当执行 dispatch_sync()时都有哪些操作,来看官方解释

当执行dispatch_sync()时,会将block里的东西作为一个任务添加到队列里,然后等block里的东西执行完返回,这就是上面介绍dispatch_sync()时说的会阻塞当前线程,因为它要等block里的东西执行完,所以现在就得把当前的线程停止,然后等block里的东西执行完。

所以把block里的任务添加到队列后,当前队列(主队列)就停了,咱们已经把任务添加到了主队列

那么咱们知道主队列里的任务,只能由主线程来完成,但是现在主线程已经阻塞停止了,所以没有线程去执行block里的内容,block里的东西不执行完,主线程就不结束当前的停止状态,结果就陷入死循环了 ~


所以其实下图的代码就已经构成死循环的条件了

当然不是只有主队列,主线程能产生类似的死锁,别的线程也一样,如下图


补充: 所以任务派发和队列形成了四中组合

dispatch_sync   串行队列   只有一只手的人,从管里取土豆,只能一个取完再取一个

dispatch_sync   并行队列   只有一只手的人,从盆里取土豆,只有一只手,所以也只能一个取完,再取一个

dispatch_async   串行队列   只有一只手的人,从管里取土豆,手很多,但是,从管里取,其余的手白搭,用不到

dispatch_async   并行队列   只有一只手的人,从盆里取土豆,好几只手,都从盆里抓土豆

综上所述,只有dispatch_async &并行队列组合,才能开辟多线程同时执行多个任务

你可能感兴趣的:(GCD中Dispatch产生死锁的原因--不忽悠)