“少侠,GCD的基本功,练的怎么样了?”
“经过一段时间的勤学苦练,我已经炉火纯青了,处理问题又快又稳,小师妹都对我刮目相看了呢”
“真是可喜可贺,预祝少侠早日赢得伊人芳心。今天老夫来再来祝你一臂之力,少走弯路,避开魔道。”
“魔道? 没遇到啊”
“少侠请看”
NSLog(@"画方");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"画圆");
});
NSLog(@"吹口哨");
“鹅.... 这个怎么感觉跟我平时使用的不一样呢,dispatch_sync同步遇见主线程会发生什么呢。小生愚钝,还请大师指点”
“要弄清楚这个问题,首先要搞清楚,这段代码运行的在主队列,串行队列还是并行队列,不同队列也会导致不同结果。”
在主队列执行
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"画方");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"画圆");
});
NSLog(@"吹口哨");
}
//输出
画方
上面的代码输出“画方”,然后程序卡死在 dispatch_sync这一行。后面的任务再也执行不了。
“大师,为什么会这样呢”
“先来复习一下,GCD的基本招式。”
dispatch_async(queue,block)
dispatch_sync(queue,block)
这两个方法的功能是把 block中要执行的任务,放到指定的queue中。
dispatch_async(queue,block),会立即返回,不等block执行。
dispatch_sync(queue,block),会阻塞当前线程,等待block执行完成。
代码在viewDidLoad中执行,即在主线程中执行。画方可以顺利执行,之后执行到dispatch_sync,这个代码在主线程中执行,把block任务也放到主线程执行。主线程是串行队列,前面一个任务执行完成之后,才能执行后面的任务,在这里,dispatch_sync在前面,而被加入到主线程的block在后面,所以正常流程是dispatch_sync,然后执行block,但dispatch_sync必须等待block执行完成后,才会执行完成,而根据串行队列FIFO的规则,block必须等待dispatch_sync执行完成之后自己才能执行。这里就造成了死锁。代码卡死在dispatch_sync这一行。
![](https://img.haomeiwen.com/i13287989/aebcf2e4c32dfa47.png)
在并行队列执行
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSLog(@"画方");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"画圆");
});
NSLog(@"吹口哨");
});
//输出
画方
画圆
吹口哨
在并行队列中时,画方先执行,dispatch_sync会等待block中的任务画圆在主队列中完成之后,继续执行吹口哨,因为这三个任务都在并行队列中,所以不会存在死锁,程序正常执行。
![](https://img.haomeiwen.com/i13287989/5b2e0f61e6b94f5b.png)
“原来如此,多谢大师指点,让我没有误入魔道。”
dispatch_sync 文档中如下解释:
Calls to dispatch_sync() targeting the current queue will
result in dead-lock
假设当前代码在queueA中执行,当用 dispatch_sync把block放到当前队列queueA中时,就会产生死锁。
下面这种情况也会产生死锁。
dispatch_queue_t queue = dispatch_queue_create("com.test.gcd", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"画方");
dispatch_sync(queue, ^{
NSLog(@"画圆");
});
NSLog(@"吹口哨");
});
//输出
画方
程序卡死在dispatch_sync这一行。
“知道了个中原理,遇到问题就能轻松化解了。未来的修炼之路已经给你指名,快快修炼去罢。”
网友评论