GCD的使用及死锁产生原因分析

一、什么是GCD?

GCD全称Grand Central Dispatch。它是苹果为多核的并行运算提出的解决方案,所以会自动合理地利用更多的CPU内核(比如双核、四核),最重要的是它会自动管理线程的生命周期(创建线程、调度任务、销毁线程),完全不需要我们管理,我们只需要告诉干什么就行。Grand Central DispatchNSOperationQueue是iOS平台上最常用的并发编程API,而NSOperationQueue是基于GCD进行封装,本文通过GCD介绍iOS并发编程的基础概念和常见的死锁产生原因。

二、相关概念

GCD中有2个核心概念:任务、队列。

  • 任务:执行什么操作。
  • 队列:用来存放任务。

下面简单介绍下相关概念。

任务

分为同步任务和异步任务。

同步任务:就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回,程序也不会接着往下执行。按照这个定义,其实绝大多数函数都是同步调用。对应API:dispatch_sync(<#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)

异步任务

异步任务:当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调(Handler机制)来通知调用者。对应API:dispatch_async(<#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)

队列

分为串行队列和并行队列。

串行队列:串行队列的特点是队列内的线程是一个一个执行,直到结束。
代表队列为系统默认提供的主队列,对应获取API:dispatch_get_main_queue()

并行队列:并行队列的特点是可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)。
注意:并发功能只有在异步(dispatch_async)函数下才有效,因为异步函数才具备开启新线程的能力(并不一定会开启新线程),而同步函数只能在当前线程中执行不具备开启线程的能力。
代表队列为系统默认提供的全局并行队列,对应获取API:dispatch_get_global_queue(<#long identifier#>, <#unsigned long flags#>)

除了以上两个系统默认提供的队列外,还可以手动创建相关队列,自定义串行或并行。

  //串行队列
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
  //并行队列
  dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);

根据任务和队列组合总共有以下4种情况:

同步执行 异步执行
串行队列 当前线程,一个一个执行 其他线程,一个一个执行
并行队列 当前线程,一个一个执行 开很多线程,一起执行

三、什么是死锁

死锁(deadlock) 通常是当多个线程在相互等待着对方的结束时,就会发生死锁,这时程序可能会被卡住。此时就导致了deadlock!

死锁产生的常见原因是在当前串行队列里面同步执行任务,比如在主线程执行如下代码就会造成死锁:

NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
   NSLog(@"2");
});

这是由于在主线程同步执行((dispatch_sync(<#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>))任务,这会导致主队列被阻塞,然后在主队列已经阻塞的情况下,将任务加入主队列(dispatch_get_main_queue(),导致程序无法继续运行。解决方法是异步执行任务或者将任务加入其他队列。

参考资料:
关于iOS多线程,你看我就够了
GCD死锁大作战

转载请注明出处:
GCD的使用及死锁产生原因分析

你可能感兴趣的:(GCD的使用及死锁产生原因分析)