GCD死锁问题

107 阅读2分钟
  1. 同步主队列执行任务。

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

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

dispatch_sync 函数本身是放在主线程中执行的,也就是说他本身也是属于主线程执行任务的一部分。根据主线程的特点:主线程会等主线程上的代码执行完毕之后才会去执行放置到主队列中的 task;再根据 disptach_sync 函数特点, task 不执行完毕,dispatch_sync 函数不返回。这样,dispatch_sync 为了返回会等 task 执行完毕也就是主线程执行完,而 task 执行又等着主线程上的代码执行完,也即主线程上 dispatch_sync 代码执行完。

  • 主队列和主线程相互等待会造成死锁
dispatch_sync(dispatch_get_main_queue(), ^(void){
NSLog(@"这里死锁了"); 
});                                                                           
NSLog(@"下面的不执行了");

解决方案:

dispatch_async(dispatch_get_main_queue(), ^(void){
NSLog(@"这里死锁了"); // 现在没有死锁 
});

dispatch_sync(dispatch_get_global_queue(0, 0), ^(void){
NSLog(@"这里死锁了"); // 现在没有死锁 
});
  1. 异步中包含同步,并且用的都是串行队列

异步串行队列中遇到同步串行。同步执行阻塞线程,需要等待block 执行完往下执行,下面又先添加到串行队列,需要执行完才能执行同步任务。解决方案, 1. 异步和同步使用不同的队列。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

解决方案:

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
  1. 阻塞主队列,同步主队列任务死锁。
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

总结:

造成死锁的原因是:

在同一个串行的队列中,同步添加block。