基本的数据结构
GCD的类都是struct定义的。
- 包括所有的父类的数据成员,都平铺重复的写在一个个的struct中。
- 提高效率,避免引入继承机制带来的代码执行上的延迟.
- 为了减少代码量和易读性,做了许多宏定义。
dispatch_object_t
GCD中类都继承自统一的基类dispatch_object_t
。是一个联合union,作用和基类指针相似,所有的子类型都可以用dispatch_object_t统一表示。
_os_object_s
表示系统对象的基类_os_object_s
。
dispatch_continuation_s
向queue提交的任务,无论block还是function形式,最终都会被封装为dispatch_continuation_s。
保存block的上下文环境和block执行函数等。
dispatch_queue_s
GCD中的queue。
dispatch_queue_attr_s
GCD中的队列的属性与状态。
GCD线程概况
在GCD中一共有2个线程池管理着任务,一个是主线程池,另一个就是除了主线程任务的线程池。主线程池由序号1的队列管理,其他有序号2的队列进行管理。加上runloop运行的runloop队列,一共就有16个队列。
1号 main queue,2号 manager queue,3没有使用,4到11表示global queue,再往后就是用户自定义queue了。
application启动的时候就会初始化这些root队列的_dispatch_root_queues_init
函数。
GCD用到的queue,无论是自己创建的,或是获取系统的main queue还是global queue,其最终都是落脚于GCD root queue中。可以在代码中的任意位置创建queue,但最终GCD管理的,就这(4到15)12个root queue,分别有不同的优先级和序列号。这种思路有点类似于命令模式,即分散创建,集中管理。
dispatch_queue_create
用户要创建一个queue的时候,需要指定target queue
,即创建的queue最终是在哪个queue上执行的,这个target queue会取root queue之一。
调用dispatch_queue_create
,GCD内部会调用_dispatch_queue_create_with_target
, 它首先会根据我们创建的queue的属性:DISPATCH_QUEUE_SERIAL
或DISPATCH_QUEUE_CONCURRENT
,到root queue数组中取出一个对应的queue作为target queue。然后,会新建一个dispatch_queue_t
对象,并设置其target queue
,返回给用户。同时,在GCD内部,新建的queue还会被加入introspection queue列表中
dispatch_get_global_queue
首先将外部传入的queue优先级转换为GCD内部的优先级dispatch_qos_t qos
。 然后,在调用_dispatch_get_root_queue
获取root queue中对应的queue。
dispatch_get_main_queue
main queue是由系统在main()方法调用前创建的。专门绑定到main thread上。而且,为了触发提交到main queue上的block,和其他queue不一样,main queue上的任务是依赖于main runloop触发的
。
application启动的时候就会初始化这些root队列的_dispatch_root_queues_init
函数。
dispatch_sync
dispatch_sync直接调用的是dispatch_sync_f
装入到自定义的任务和方法都被封装成 dispatch_continuation_t
结构体后,扔到其挂靠的root队列里去,所以自己创建的队列只是一个代理人身份,真正的管理人是其对应的root队列。
最后通过_dispatch_continuation_pop
方法把事件压入队列执行
_dispatch_sync_wait
检测死锁的函数
dispatch_async
无论“线程标示”是什么类型的queue,GCD首先会将传入队列和方法打包成dispatch_continuation_t
类型,然后调用方法_dispatch_continuation_async
。
dispatch_async底层运用了线程池,会在和当前线程不同的线程上处理任务。
串行任务:
将block打包成dispatch_continuation_t
, 然后把dispatch_queue_t
通过_dispatch_continuation_push
入队到响应的root queue中,root queue中的线程池中的线程会被唤醒,执行线程函数_dispatch_worker_thread3
,root queue会被倾倒,执行queue中的任务。
并行任务:
将block打包成dispatch_continuation_t
,然后并行队列会走 _dispatch_async_f2
首先会被替换为对应的root queue,将自定义dispatch_queue_t入队。如果是第一次入队,则会去激活所有的root queue,即创建XUN 内核支持的workqueue(升级版线程池,会自动判断是否需要创建新的线程),然后将workqueue的工作函数设置为_dispatch_worker_thread3
。_dispatch_worker_thread3 会调用_dispatch_root_queue_drain
,将root queue进行清空,它会清空所有提交到当前root queue中的dispatch_queue_t,并执行它们的dq任务。
dispatch_once
#define dispatch_once _dispatch_once
是一个宏定义
当单例方法执行完毕,GCD会将onceToken置为~0。如果再次调用单例方法,GCD会发现onceToken已经使用过,就直接返回了,并且用原子操作防止多线程下多次调用。
dispatch_group
dispatch_group的相关函数是通过dispatch_semaphore
控制的
dispatch_group_create
创建一个dispatch_group_t
类型实例并返回。实际是创建了一个信号量 通过_dispatch_semaphore_class_init
控制的
dispatch_group_wait
内部是调用的_dispatch_group_wait_slow
dispatch_semaphore_create
调用_dispatch_semaphore_class_init
dispatch_semaphore_wait
调用_dispatch_group_wait_slow
dispatch_barrier_async
dispatch_async直接把任务扔到root队列,而dispatch_barrier_async是把任务在到自定义的队列。