1、同步串行主队列
dispatch_sync(dispatch_get_main_queue(), ^(void){
NSLog(@"这里死锁了");
});
因为dispatch_sync是一个同步队列,所以会堵塞在这里,直至这个dispatch_sync有返回才会继续执行下去,此时这个block是加入到主队列里面,并且后面的代码在block之前加入到主队列,然而主队列是一个FIFO的串行队列,所以block需要后面的代码先执行,但是由于这个dispatch_sync阻塞了,所以后面的代码又没法执行,所以导致相互阻塞了。
解决方案
- 切换成异步队列
dispatch_async(dispatch_get_main_queue(), ^(void){
NSLog(@"这里死锁了"); // 现在没有死锁
});
- 换一个队列,不添加到主队列
dispatch_sync(dispatch_get_global_queue(0, 0), ^(void){
NSLog(@"这里死锁了"); // 现在没有死锁
});
2、异步执行同步串行队列(任意队列)
dispatch_queue_t queue = dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);
NSLog(@"1");//任务1
dispatch_async(queue,^{
NSLog(@"2");//任务2
dispatch_sync(queue,^{
NSLog(@"3");//任务3
});
NSLog(@"4");//任务4
});
NSLog(@"5");//任务5
// 1
// 5
// 2
首先任务1正常执行;
因为dispatch_async是一个异步线程,不会堵塞线程,所以任务5也正常执行;
进入dispatch_async里面,任务2可以直接执行;
然后是一个同步线程,并且queue是一个串行队列,遵循FIFO,此时同步线程会阻塞线程,任务3加入到queue队列中,但是任务4又是优先于3加入queue,所以任务3需要等待任务4执行完才执行,但是任务3又堵塞了线程,所以任务4也不能执行,这样相互堵塞造成死锁。
解决方案
- 将异步线程和同步线程放在不同的队列
dispatch_queue_t queue = dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);
NSLog(@"1");//任务1
dispatch_async(queue,^{
NSLog(@"2");//任务2
dispatch_sync(dispatch_get_main_queue(),^{
NSLog(@"3");//任务3
});
NSLog(@"4");//任务4
});
NSLog(@"5");//任务5
// 1
// 5
// 2
// 3
// 4
- 将串行队列换成并发队列
dispatch_queue_t queue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");//任务1
dispatch_async(queue,^{
NSLog(@"2");//任务2
dispatch_sync(queue,^{
NSLog(@"3");//任务3
});
NSLog(@"4");//任务4
});
NSLog(@"5");//任务5
// 1
// 5
// 2
// 3
// 4
3、堵塞主队列,同步主队列任务死锁
dispatch_async(dispatch_get_global_queue(0,0),^{
NSLog(@"1");//任务1
dispatch_sync(dispatch_get_main_queue(),^{
NSLog(@"2");//任务2
});
NSLog(@"3");//任务3
});
NSLog(@"4");//任务4
while(1){
}
NSLog(@"5");//任务5
// 4
// 1
首先是一个异步线程里的全局队列,不会堵塞,所以任务4可以执行;
异步线程里面任务1也可以执行,任务1、4顺序不固定;
然后主线程里的while循环堵塞主队列,但是异步线程的任务2也是加入到主队列里的,并且是在while循环任务之后,while堵塞,任务5无法执行,所以任务2也没法执行,任务2不能返回,那么任务3也不能执行。
- 用一个并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue,^{
NSLog(@"1");//任务1
dispatch_sync(queue,^{
NSLog(@"2");//任务2
});
NSLog(@"3");//任务3a
});
NSLog(@"4");//任务4
while(1){
}
NSLog(@"5");//任务5
// 4
// 1
// 2
// 3
测试发现如果把queue换成一个自定义的串行队列,结果也只会打印4和1,任务2会死锁,所以可知全局队列是一个并发队列。
总结
造成死锁的原因是:在同一个串行的队列中,同步添加block。