美文网首页iOS面试系列
iOS 多线程GCD主线程上同步执行主队列方法卡死的解释

iOS 多线程GCD主线程上同步执行主队列方法卡死的解释

作者: 齐玉婷 | 来源:发表于2019-05-14 17:25 被阅读0次

我们都知道,在主线程上,同步执行,为主队列添加 task 会导致卡死。

到底该怎么理解呢?

第一 

主线程有一个特点:主线程会先执行主线程上的代码片段,然后才会去执行放在主队列中的任务。

第二

同步执行  dispatch_sync函数的特点:该函数只有在该函数中被添加到某队列的某方法执行完毕之后才会返回。即 方法会等待 task 执行完再返回

主线程执行为主队列添加任务

具体分析:

dispatch_sync 函数本身是放在主线程中执行的,也就是说他本身也是属于主线程执行任务的一部分。根据主线程的特点:主线程会等主线程上的代码执行完毕之后才会去执行放置到主队列中的 task;再根据 disptach_sync 函数特点, task 不执行完毕,dispatch_sync 函数不返回。这样,dispatch_sync 为了返回会等 task 执行完毕也就是主线程执行完,而 task 执行又等着主线程上的代码执行完,也即主线程上 dispatch_sync 代码执行完。

主队列中的任务必须按顺序挨个执行

任务要等主线程有空的时候(即主队列中的所有任务执行完)才能执行

主线程要执行完“结束标志”的任务后才有空

“任务”和“结束标志”两个任务互相等待,造成死锁

结果

卡死的原因已经说明清楚了。

现在来证明上面两点

第一:主线程执行特点,先执行主线程上的代码,再执行主队列中的任务。

-------划重点了!  这里强调~~~~~>  主队列 ! 主队列 ! 主队列 !

如果是串行队列,在主线程上同步方法添加一个任务到串行队列。

主线程上为串行队列添加任务 结果

不会死锁那说明,没有出现上面说的互相等待的问题,我们来分析一下。

首先,dispatch_sync 函数的特性没变,等待 task 执行完毕之后才能返回。

既然,程序能正常运行,那么必然 dispatch_sync 函数等到了 task 的返回。

从结果输出的顺序看出,  同步执行串行队列的实质为

所以在上面会强调主队列等待,普通串行队列不等待主线程代码的执行。

主线程会先执行完主线程上的代码,然后再执行主队列中的方法!!

我们怎么证明呢?要知道在主线程上同步为主队列添加 task 会死锁。

那么,我们在主线程上异步为主队列添加 task

task 被异步添加到主队列 结果

结果好像是按照我们预期那样执行的,先执行主线程上代码在执行主队列中 task。 

可是,仅仅这样就判定主线程会先执行主线程中代码再执行主队列中的 task 还不准确。 

首先,dispatch_async 函数的功能,我们都会想到,觉得是否开启新的线程去执行队列中的任务。其实还有一点,那就是这个函数本身不会阻塞线程的执行,不同于上述 dispatch_sync,dispatch_sync 会阻塞线程,知道里面的 task 执行完毕后才返回。这个特性在主线程乃至子线程都奏效。

所以,执行到dispatch_async函数时不等待 task 执行直接接着执行后面的代码。考虑到队列中 task 调用问题(这是需要 cpu 调度的,会消耗一定时间),我们在原代码基础之上,dispatch_async函数之后然线程 sleep 一会,看添加到主队列中的 task 是否真正在等待主线程上代码的执行。

继续验证

结果和刚才一样,证明异步执行的时候,主队列的 task 会等待主线程的代码执行 结果

那么我们就证明了,主线程确实会先执行完主线程上代码再执行主队列中的 task(因为 dispatch_async 不会等待函数中被添加到某队列的某方法执行完毕之后才会返回),  主队列又叫全局串行队列。

我们解决死锁的方法,通常是把死锁方法放到子线程里面执行。

为什么现在就不会死锁了呢?

子线程同步执行,一样阻塞, dispatch_async函数会阻塞下面 NSLog 方法进行输出,dispatch_async函数结束的时刻是里面 task 执行完毕的时刻,

dispatch_async将 task 放入主队列中,主队列等待主线程上代码执行完毕之后,再执行主队列中的 task ,主队列中的 task 执行完毕之后再跳出dispatch_async函数之后子线程最后的 NSLog 方法。

证明:

主线程代码进行 3s 的 sleep 结果和预期一样

接下来在子线程上把同步方法换成异步方法呢?

子线程不阻塞,接着执行,然后 sleep 3s ,执行主线程代码,最后是主队列task 结果

以后我们再见到dispatch_async 或者dispatch_sync时,除了要考虑他们是否会开启新的线程之外,还应该记住:

dispatch_async不阻塞当前线程

dispatch_sync阻塞当前线程

相关文章

  • ios知识点(9)多线程

    iOS多线程GCD详解 使用GCD iOS多线程中,队列和执行的排列组合结果分析 存在一点小瑕疵,如果同步(syn...

  • iOS开发多线程之GCD

    iOS开发多线程之GCDiOS开发之GCD同步任务加强iOS开发之GCD串行队列iOS开发之GCD并发队列 GCD...

  • GCD练习

    GCD练习 ios 多线程 GCD : ios 多线程 全剧队列,异步执行 线程间通信 信号量 文件锁 单利模式 ...

  • iOS开发之GCD并发队列

    iOS开发多线程之GCDiOS开发之GCD同步任务加强iOS开发之GCD串行队列iOS开发之GCD并发队列 03 ...

  • 多线程

    iOS中的几种多线程GCD1、GCD分为任务和队列,任务(同步,异步)队列(串行,并发),同步串行,同步主队列的情...

  • iOS开发之GCD同步任务加强

    iOS开发多线程之GCDiOS开发之GCD同步任务加强iOS开发之GCD串行队列iOS开发之GCD并发队列 004...

  • iOS开发之GCD串行队列

    iOS开发多线程之GCDiOS开发之GCD同步任务加强iOS开发之GCD串行队列iOS开发之GCD并发队列 实例d...

  • iOS 多线程GCD主线程上同步执行主队列方法卡死的解释

    我们都知道,在主线程上,同步执行,为主队列添加 task 会导致卡死。 到底该怎么理解呢? 第一 主线程有一个特点...

  • 多线程知识整理

    iOS中的常见多线程方案 GCD中的2个用来执行任务的函数 用同步的方式执行任务 queue : 队列block ...

  • iOS开发—GCD笔记

    多线程,主GCD 串行队列(Serial Dispatch Queue,等待现有处理结束) 并行队列�(Concu...

网友评论

    本文标题:iOS 多线程GCD主线程上同步执行主队列方法卡死的解释

    本文链接:https://www.haomeiwen.com/subject/entraqtx.html