GCD内部实现--摘自《iOS与OS X多线程和内存管理》
GCD 基本介绍
(1)iOS和OS X系统是基于XNU内核实现的。
(2)用于实现 GCD Queue 的组件是:
组件名称 | 提供技术 |
---|---|
Libdispatch | Dispatch queue |
Libc(pthread) | pthread_workqueue |
XNU内核 | workqueue |
常用的 GCD API 都包含在 libdispatch 库中的 C 语言函数,dispatch queue 通过结构体和链表,被实现成 FIFO 的队列。FIFO 的队列用来管理通过 dispatch_async 等函数追加的 Block。
Block 并不是直接加入 FIFO 的队列,而是先加入 Dispatch Continuation 这一个 dispatch_continuation_t类型结构体中,然后再加入 FIFO的队列。 Dispatch Continuation 用于记忆Block所述的Dispatch Group 和其他的一些信息,相当于我们常说的执行上下文。
Dispatch Queue 可通过 dipatch_set_target_queue 函数设定,可以设定执行该 Dispatch Queue 处理的 Dispatch Queue 为目标。该目标可像串珠子一样,设定多个连接在一起的 Dispatch Queue,但是在连接串的最后必须设定为 Main Dispatch Queue,或各种优先级的 Global Dispatch Queue,或是准备用于 Serial Dispatch Queue 的各种优先级的Global Dispatch Queue。
然后,Main Dispatch Queue 在RunLoop中执行 Block。
Global Dispatch Queue优先级及生成
Global Dispatch Queue有如下8种:
Global Dispatch Queue (High priority)
Global Dispatch Queue (Default priority)
Global Dispatch Queue (Low priority)
Global Dispatch Queue (Background priority)
Global Dispatch Queue (High overcommit priority)
Global Dispatch Queue (Default overcommit priority)
Global Dispatch Queue (Low overcommit priority)
Global Dispatch Queue (Background overcommit priority)
注意前面四种 和后面四种不同优先级的 Queue 有一词之差: Overcommit。其区别就在于 Overcommit Queue 不管系统状态如何都会强制生成线程队列。
这 8 种 Global Dispatch Queue 各使用一个 pthread_workqueue。GCD 初始化时,使用 pthread_workqueue_create_np 函数生成 pthread_wrokqueue。
pthread_wrokqueue 包含在 Libc 提供的 pthreads API 中。它通过系统的 bsdthread_register 和workq_open 函数调用,在初始化 XNU 内核的 workqueue 之后获取其信息。
XNU 内核有 4 种 workqueue:
WORKQUEUE_HIGH_PRIOQUEUE
WORKQUEUE_DEFAULT_PRIOQUEUE
WORKQUEUE_LOW_PRIOQUEUE
WORKQUEUE_BG_PRIOQUEUE
以上为 4 种执行优先级的 workqueue。该执行优先级与 Global Dispatch Queue 的 4 种执行优先级相同。
Dispatch Queue 中执行 Block 的过程。
当在 Global Dispatch Queue 中执行Block时,libdispatch 从 Global Dispatch Queue 自身的 FIFO 队列取出 Dispatch Continuation,调用pthread_workqueue_additem_np 函数。将该 Global Dispatch Queue 本身、符合其优先级的 workqueue 信息以及执行Dispatch Continuation的回调函数等传递给参数。
pthread_workqueue_additem_np 函数使用 workq_kernreturn 系统调用,通知 workqueue 增加应当执行的项目。根据该通知,XNU内核基于系统状态判断是否要生成线程。如果是 Overcommit 优先级的 Global Dispatch Queue ,workqueue 则始终生成线程。
另外,因为 workqueue 生成的线程在实现用于 workqueue 的线程计划表中运行,他的上下文切换(shift context)与普通的线程有很大的不同。这也是我们使用GCD的原因。
workqueue 的线程执行 pthread_workqueue 函数,该函数调用libdispatch 的回调函数。在该回调函数中执行加入到 Global Dispatch Queue中 的下一个Block。