“少侠,GCD的基本功,练的怎么样了?”bash
“通过一段时间的勤学苦练,我已经炉火纯青了,处理问题又快又稳,小师妹都对我另眼相看了呢”async
“真是可喜可贺,预祝少侠早日赢得伊人芳心。今天老夫来再来祝你一臂之力,少走弯路,避开魔道。”spa
“魔道? 没遇到啊”线程
“少侠请看”code
NSLog(@"画方");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"画圆");
});
NSLog(@"吹口哨");
复制代码
“鹅.... 这个怎么感受跟我平时使用的不同呢,dispatch_sync同步碰见主线程会发生什么呢。小生愚钝,还请大师指点”cdn
“要弄清楚这个问题,首先要搞清楚,这段代码运行的在主队列,串行队列仍是并行队列,不一样队列也会致使不一样结果。”blog
在主队列执行队列
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"画方");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"画圆");
});
NSLog(@"吹口哨");
}
//输出
画方
复制代码
上面的代码输出“画方”,而后程序卡死在 dispatch_sync这一行。后面的任务再也执行不了。文档
“大师,为何会这样呢”get
“先来复习一下,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这一行。
在并行队列执行
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSLog(@"画方");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"画圆");
});
NSLog(@"吹口哨");
});
//输出
画方
画圆
吹口哨
复制代码
在并行队列中时,画方先执行,dispatch_sync会等待block中的任务画圆在主队列中完成以后,继续执行吹口哨,由于这三个任务都在并行队列中,因此不会存在死锁,程序正常执行。
“原来如此,多谢大师指点,让我没有误入魔道。”
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这一行。
复制代码
“知道了个中原理,遇到问题就能轻松化解了。将来的修炼之路已经给你指名,快快修炼去罢。”