在上一篇文章 介绍syn/asyn和queue的各种搭配时,提到有产生死锁崩溃的情况,现简单介绍下。
例1
- (void)viewDidLoad
{
NSLog(@"---1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"---2");
});
NSLog(@"---3");
});
打印了1,并不会打印2和3,会死锁崩溃,因为dispatch_sync是同步,会阻塞当前主线程,等代码块里面内容执行完后再往下继续执行,然而根据dispatch_get_main_queue判断,代码块内的代码又需在主线程中执行,主线程已被阻塞了,所以代码块处于永远等待中。
例2
- (void)viewDidLoad {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"----1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"----2");
});
NSLog(@"---3");
});
NSLog(@"---4");
while (YES) {}
}
2和3永远不会被打印,因为1在异步子线程中执行,所以可能1比4先打印。
这种情况下,因为2需要在主线程中同步执行,当打印了1后,把异步代码放到后台等待获取主线程,先执行4。然而遇到个死循环阻塞了主线程,而2又需要主线程才能执行,所以2处于永远等待获取主线程。
例3
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
3和4永远不会被打印被锁死,因为
2会在主线程里面打印,然后遇到dispatch_sync,队列会被阻塞,等待代码块3执行完了再往下面执行
而3又需要获取到主队列才能执行,然而队列已被阻塞。
例4
- (void)viewDidLoad {
NSLog(@"---1");
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"---2");
dispatch_sync(dispatch_get_global_queue(0,0), ^{
NSLog(@"---3");
});
NSLog(@"---4");
});
NSLog(@"---5");
}
这里会按照顺序打印 1,2,3,4,5,并且都在主线程中打印。
因为2,3都不会开子线程(在当前线程中执行),由于是串行,所以会阻塞当前线程,然而队列都是global(虽有并发能力,但基于是sync,所以不会开线程),在当前线程(主),串行执行。
例5
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"---1");
[self performSelector:@selector(pintLog) withObject:nil afterDelay:2];
NSLog(@"---3");
});
}
-(void)pintLog{
NSLog(@"---2");
}
会打印1,3,永远不会打印2,因为GCD创建的线程没有RunLoop,然而performSelector这类方法需要在RunLoop里面执行,所以代码会失效。
总结:
根据dispatch_async和dispatch_sync判断是否会阻塞线程。
根据queue判断是否开线程/还是当前线程执行。
有什么错误欢迎批评指正 。