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

GCD主线程上同步执行主队列方法卡死的解释_第1张图片

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

到底该怎么理解呢?

第一 

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

第二

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


好了,有了这两点,死锁的问题就解决了。


GCD主线程上同步执行主队列方法卡死的解释_第2张图片
注释里面分析了死锁原因


GCD主线程上同步执行主队列方法卡死的解释_第3张图片
结果

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

现在来证明上面两点————————————

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

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

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


首先我们知道程序不会死锁,不会开启线程,task 在主队列中顺序执行


GCD主线程上同步执行主队列方法卡死的解释_第4张图片

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

首先,dispatch_sync 函数的特性没变

等待 task 执行完毕之后才能返回

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

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


GCD主线程上同步执行主队列方法卡死的解释_第5张图片
所以在上面会强调主队列等待,普通串行队列不等待主线程代码的执行。

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

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

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


GCD主线程上同步执行主队列方法卡死的解释_第6张图片
task 被异步添加到主队列


GCD主线程上同步执行主队列方法卡死的解释_第7张图片


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

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

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

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


GCD主线程上同步执行主队列方法卡死的解释_第8张图片
结果和刚才一样,证明异步执行的时候,主队列的 task 会等待主线程的代码执行

那么我们就证明了,主线程确实会先执行完主线程上代码再执行主队列中的 task,  主队列又叫  全局串行队列。

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


GCD主线程上同步执行主队列方法卡死的解释_第9张图片

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

————————————————

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

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

证明:


GCD主线程上同步执行主队列方法卡死的解释_第10张图片
主线程代码进行 3s 的 sleep


GCD主线程上同步执行主队列方法卡死的解释_第11张图片
结果和预期一样

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


GCD主线程上同步执行主队列方法卡死的解释_第12张图片
子线程不阻塞,接着执行,然后 sleep 3s ,执行主线程代码,最后是主队列task



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

dispatch_async不阻塞当前线程

dispatch_sync阻塞当前线程

你可能感兴趣的:(GCD主线程上同步执行主队列方法卡死的解释)