https://github.com/xufeng79x/GCDDemo
1.简介
前接[New learn]GCD的基本使用,我们分析了GCD的一般使用方法,其中比较特殊的是在分析到主队列的时候发生了卡死现象。
本章节中将分析研究一下卡死线程发生的原理。
2.分析
从[New learn]GCD的基本使用中我们可以看出,异步执行方式无论是何种队列,无论是否开启新线程都不会发生卡死现象。原因在于如果异步执行方式将任务放入队列后可以“忍受”等待,当线程资源不足的时候可以等待线程空闲后再来执行。所以说异步不会发生卡死现象。
那么唯一我们可以推断出来的是同步执行的情况下将会发生卡死。那么同步执行在和什么队列组合的时候会发生卡死呢?
定性分析一下:
2.1 同步执行和串行队列组合:
那么为什么【同步执行+自建串行队列】不会发生卡死,而【同步执行+主队列】会发生卡死,按理说,主队列也应该是一个串行队列,因为他只在主线程中执行,换句话说,主队列是并行队列是没有任何意义的。
按照我的分析【同步执行+自建串行队列】的执行方式如同:
唯一的执行线程在两个队列间串行执行任务。
而【同步执行+主队列】得执行方式如同:
而此时由于调度的是同一个队列,队列的性质决定他必须等待前任务执行完毕后才能去执行后续任务,这样导致产生一种死锁的现象的产生。
以上纯粹是个人YY。
下面我们来使用实际例子来查看一下自己的YY是否准确:
我们在controller中根线程都是主线程,队列是主队列,为了排除这种干扰,我们在设计测试代码的时候在某个线程中在开启子线程,两者的队列一样进行同步执行操作:
/** * 同步执行下的相同串行队列的卡死分析 */ -(void) testForSyncAndSerial { // 创建队列 dispatch_queue_t queue = dispatch_queue_create("xf", DISPATCH_QUEUE_SERIAL); // 异步启动任务,他将在新的线程中执行,作为测试的根线程 dispatch_async(queue,^{ NSLog(@"execute task1 in thread : %@ start!" , [NSThread currentThread]); // 在当前线程中使用与根线程相同的串行队列进行新任务的同步执行 dispatch_sync(queue,^{ NSLog(@"execute task2 in thread : %@" , [NSThread currentThread]); }); NSLog(@"execute task1 in thread : %@ end!", [NSThread currentThread]); }); NSLog(@"%@", @"完成!"); }
结果:
-- :::] 完成! -- :::] execute task1 , name = (null)} start!
总结:
卡死现象发生!YY是正确的!!
当根线程(调度发起的线程)的串行队列与同步执行任务的串行队列为同一个队列的时候将会卡死。
那么如果换成并行队列会发生什么呢?
2.2 同步执行和并行队列组合:
按照之前分许,由于串行队列的性质决定了他必须等到前面的任务执行完毕后才能执行,所以可能会造成死锁现象,但是对于并行队列应该不会有此问题,我们加以测试:
/** * 同步执行下的相同串行队列的卡死分析 */ -(void) testForSyncAndConcurrent { // 创建队列 dispatch_queue_t queue = dispatch_queue_create("xf", DISPATCH_QUEUE_CONCURRENT); // 异步启动任务,他将在新的线程中执行,作为测试的根线程 dispatch_async(queue,^{ NSLog(@"execute task1 in thread : %@ start!" , [NSThread currentThread]); // 在当前线程中使用与根线程相同的串行队列进行新任务的同步执行 dispatch_sync(queue,^{ NSLog(@"execute task2 in thread : %@" , [NSThread currentThread]); }); NSLog(@"execute task1 in thread : %@ end!", [NSThread currentThread]); }); NSLog(@"%@", @"完成!"); }
结果:
-- :::] 完成! -- :::] execute task1 , name = (null)} start! -- :::] execute task2 , name = (null)} -- :::] execute task1 , name = (null)} end!
总结:
我们可以看到并行队列不会造成卡死现象,因为不会有死锁的条件产生。
3.总结
当根线程(调度发起的线程)的串行队列与同步执行任务的串行队列为同一个队列的时候将会卡死。