创建队列底层源码分析
通过上篇文章 iOS 深入了解 GCD 函数和队列中,我们了解函数和队列,知道队列的创建时通过 GCD 中的dispatch_queue_create
方法,下面我们在libdispatch.dylib
(libdispatch-1173.60.1) 去探索队列是如何创建的(源码下载)
- 搜索
dispatch_queue_create
arduino
dispatch_queue_t
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr) {
return _dispatch_lane_create_with_target(label, attr, DISPATCH_TARGET_QUEUE_DEFAULT, true);
}
- 搜索
_dispatch_lane_create_with_target
scss
DISPATCH_NOINLINE
static dispatch_queue_t
_dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
dispatch_queue_t tq, bool legacy) {
// dqai 创建 -
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
// 第一步:规范化参数,例如qos, overcommit, tq
...
// 拼接队列名称
const void *vtable;
dispatch_queue_flags_t dqf = legacy ? DQF_MUTABLE : 0;
if (dqai.dqai_concurrent) { //vtable表示类的类型
// OS_dispatch_queue_concurrent
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
vtable = DISPATCH_VTABLE(queue_serial);
}
....
// 开辟内存 生成响应的对象 queue
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s)); // alloc
// 构造方法
// 根据 dqai.dqai_concurrent 的值,就能判断队列是串行还是并发
_dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
(dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0)); // init
// 设置队列 label 标识符
dq->dq_label = label;
// 优先级处理
dq->dq_priority = _dispatch_priority_make((dispatch_qos_t)dqai.dqai_qos, dqai.dqai_relpri);
...
// 类似于类与元类的绑定,不是直接的继承关系,而是类似于模型与模板的关系
dq->do_targetq = tq;
_dispatch_object_debug(dq, "%s", __func__);
return _dispatch_trace_queue_create(dq)._dq;
}
【第一步】第6行通过_dispatch_queue_attr_to_info
方法传入dqa
(即队列类型,串行、并发
等)创建dispatch_queue_attr_info_t
类型的对象dqai
,用于存储队列的相关属性信息
。
_dispatch_queue_attr_to_info
方法代码如下:
【第二步】看423 ~ 430行,判断当前传入的 dqa 是串行(NULL)还是并发。如果是串行(NULL)就直接返回 dqa,否则就继续往下走看432 ~ 460行。438行是苹果的算法,441 ~ 458行是位域。
【第三步】看16行通过DISPATCH_VTABLE
拼接队列名称,即vtable
。其中DISPATCH_VTABLE
是宏定义,如下所示,队列的类型是通过OS_dispatch_
+ 队列类型queue_concurrent
拼接而成的。
串行
队列类型:OS_dispatch_queue_serial
,验证如下
并发
队列类型:OS_dispatch_queue_concurrent
,验证如下
scss
#define DISPATCH_VTABLE(name) DISPATCH_OBJC_CLASS(name)
#define DISPATCH_OBJC_CLASS(name) (&DISPATCH_CLASS_SYMBOL(name))
#define DISPATCH_CLASS(name) OS_dispatch_##name
【第四步】看26 ~ 30行通过_dispatch_object_alloc + _dispatch_queue_init
初始化队列,即dq
。其中在_dispatch_queue_init
传参中根据dqai.dqai_concurrent
的布尔值,就能判断队列是串行
还是并发
,而vtable
表示队列的类型,说明队列也是对象
。
- 进入
_dispatch_object_alloc -> _os_object_alloc_realized
方法中设置了 isa 的指向,从这里可以验证队列也是对象
的说法。
_dispatch_object_alloc
方法代码如下:
_os_object_alloc_realized
方法代码如下:
- 进入
_dispatch_queue_init
方法,队列类型是dispatch_queue_t
,并设置队列的相关属性。
【第五步】通过_dispatch_trace_queue_create
对创建的队列进行处理,其中_dispatch_trace_queue_create
是_dispatch_introspection_queue_create
封装的宏定义,最后会返回处理过的_dq
。
进入_dispatch_introspection_queue_create_hook -> dispatch_introspection_queue_get_info -> _dispatch_introspection_lane_get_info
中可以看出,与我们自定义的类还是有所区别的,创建队列
在底层的实现是通过模板创建
的。
总结
- 队列创建方法
dispatch_queue_create
中的参数二(即队列类型), 决定了下层中max & 1
(用于区分是串行还是并发), 其中1
表示串行
。 queue
也是一个对象
,也需要通过底层 alloc + init 创建, 并且在 alloc 中也有一个class
, 这个class
是通过宏定义拼接
而成,并且同时会指定isa的指向
。创建队列
在底层的处理是通过模板创建的,其类型是dispatch_introspection_queue_s
结构体。
dispatch_queue_create
底层分析流程如下图所示