使用版本:
libdispatch-1173.40.5.tar
涉及到的数据结构在我的另一篇 其他:数据结构源码解析
本篇还是我对函数源码的逐步探究, 核心内容在正文中: 正文: 以 GCD 的接口为引, 看源码实现
dispatch_get_main_queue
里面返回一个宏, 关键的地方在 _dispatch_main_q
dispatch_queue_main_t dispatch_get_main_queue(void){
return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
}
可以看到, _dispatch_main_q 直接是一个结构体的变量, 并在最开始已经做完了初始化
struct dispatch_queue_static_s _dispatch_main_q = {
DISPATCH_GLOBAL_OBJECT_HEADER(queue_main),
#if !DISPATCH_USE_RESOLVERS
.do_targetq = _dispatch_get_default_queue(true),
#endif
.dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(1) |
DISPATCH_QUEUE_ROLE_BASE_ANON,
.dq_label = "com.apple.main-thread",
.dq_atomic_flags = DQF_THREAD_BOUND | DQF_WIDTH(1),
.dq_serialnum = 1,
};
dispatch_get_global_queue
init.c
入参: long priority & unsigned long flags
核心代码: 返回一个 root_queue
return _dispatch_get_root_queue(qos, flags & DISPATCH_QUEUE_OVERCOMMIT);
从头往下看: 忽略断言部分
~是按位取反
下面的代码是判断 flags 为某个值(我没算出来),时直接返回结束,
DISPATCH_QUEUE_OVERCOMMIT = 0x2ull
if (flags & ~(unsigned long)DISPATCH_QUEUE_OVERCOMMIT)
dispatch_qos_t 的本质是整型, 这里做的操作是, 把入参的priority, 通过一个转换函数转换为另一个整型qos
内部函数可以理解为是在实现两个 enum 的转换, 将外部定义的优先级,转为内部的执行优先级
qos(quality-of-service) 官方文档有提到:Apple Developer Documentation,其实就是线程中优先级的意思
typedef uint32_t dispatch_qos_t;
dispatch_qos_t qos = _dispatch_qos_from_queue_priority(priority);
这些判断结束后, 就是返回_dispatch_get_root_queue
完整代码如下:
dispatch_queue_t dispatch_get_global_queue(long priority, unsigned long flags)
{
dispatch_assert(countof(_dispatch_root_queues) ==
DISPATCH_ROOT_QUEUE_COUNT);
if (flags & ~(unsigned long)DISPATCH_QUEUE_OVERCOMMIT) {
return DISPATCH_BAD_INPUT;
}
dispatch_qos_t qos = _dispatch_qos_from_queue_priority(priority);
#if !HAVE_PTHREAD_WORKQUEUE_QOS
if (qos == QOS_CLASS_MAINTENANCE) {
qos = DISPATCH_QOS_BACKGROUND;
} else if (qos == QOS_CLASS_USER_INTERACTIVE) {
qos = DISPATCH_QOS_USER_INITIATED;
}
#endif
if (qos == DISPATCH_QOS_UNSPECIFIED) {
return DISPATCH_BAD_INPUT;
}
return _dispatch_get_root_queue(qos, flags & DISPATCH_QUEUE_OVERCOMMIT);
}
_dispatch_get_root_queue & _dispatch_root_queues
这个函数直接看源码, 内部是返回一个变量, 这个变量在开始就已生成 _dispatch_root_queues
static inline dispatch_queue_global_t _dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit)
{
if (unlikely(qos < DISPATCH_QOS_MIN || qos > DISPATCH_QOS_MAX)) {
DISPATCH_CLIENT_CRASH(qos, "Corrupted priority");
}
return &_dispatch_root_queues[2 * (qos - 1) + overcommit];
}
其中两个宏被我放到了 其他: 数据结构使用的宏 中解析要注意的是
每个优先级,都会有另一个这个 优先级名字+overcommit 的下一级优先级
在一些参考文章中看到(有overcommit标记的队列会在任务提交时新创建一个线程), 暂时不知道怎么求证
整体优先级如下:enum { DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS = 0, DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS, DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS, DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS, DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS, DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS, DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS_OVERCOMMIT, _DISPATCH_ROOT_QUEUE_IDX_COUNT, };
这整个 数组变量_dispatch_root_queues[], 内部通过MAINTENANCE 这类第一个参数, 生成dispatch_queue_global_s变量
然后通过MAINTENANCE, 0第一个第二个参数组合, 计算出在数组中的序号
struct dispatch_queue_global_s _dispatch_root_queues[] = {
_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, 0,
.dq_label = "com.apple.root.maintenance-qos",
.dq_serialnum = 4,
),
_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.maintenance-qos.overcommit",
.dq_serialnum = 5,
),
_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, 0,
.dq_label = "com.apple.root.background-qos",
.dq_serialnum = 6,
),
_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.background-qos.overcommit",
.dq_serialnum = 7,
),
_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, 0,
.dq_label = "com.apple.root.utility-qos",
.dq_serialnum = 8,
),
_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.utility-qos.overcommit",
.dq_serialnum = 9,
),
_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT, DISPATCH_PRIORITY_FLAG_FALLBACK,
.dq_label = "com.apple.root.default-qos",
.dq_serialnum = 10,
),
_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT,
DISPATCH_PRIORITY_FLAG_FALLBACK | DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.default-qos.overcommit",
.dq_serialnum = 11,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, 0,
.dq_label = "com.apple.root.user-initiated-qos",
.dq_serialnum = 12,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.user-initiated-qos.overcommit",
.dq_serialnum = 13,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, 0,
.dq_label = "com.apple.root.user-interactive-qos",
.dq_serialnum = 14,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.user-interactive-qos.overcommit",
.dq_serialnum = 15,
),
};
dispatch_queue_create & dispatch_queue_create_with_target
这两函数, 实际都是在调用 _dispatch_lane_create_with_target
_dispatch_lane_create_with_target(
const char *label,
dispatch_queue_attr_t dqa,
dispatch_queue_t tq,
bool legacy
)
不同在于 dispatch_queue_create 入参为
_dispatch_lane_create_with_target(label, attr, DISPATCH_TARGET_QUEUE_DEFAULT, true);
dispatch_queue_create_with_target 入参为
_dispatch_lane_create_with_target(label, dqa, tq, false);
看完函数后会结合数据结构 dispatch_queue_attr_s : 会发现第三个参的dispatch_queue_t tq 就是最后创建的 queue 中的dq->do_targetq = tq;
在创建过程中, tq 一旦是空的, 最终创建的 queue, do_targetq 都会变成根据 qos 在 _dispatch_get_root_queue中查找
//dispatch_queue_create 时就是空的
#define DISPATCH_TARGET_QUEUE_DEFAULT NULL
if (!tq) {
tq = _dispatch_get_root_queue(
qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos,
overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;
可以理解为创建的队列在默认情况下, 最终都是在一个队列里执行的(某个 root queue)
自定义的队列在最终都会被归为 root 中某个队列中执行
最后看代码(省略了大部分判断过程)
static dispatch_queue_t _dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
dispatch_queue_t tq, bool legacy) {
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
//...qos 计算
// tq 判校验,判空处理等
// 一旦上面将 tq 设为空,或者传入的是空, 都是从 root_queue 取东西
if (!tq) {
tq = _dispatch_get_root_queue(
qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos,
overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;
}
// 根据 并行/串行 初始化虚函数表
const void *vtable;
dispatch_queue_flags_t dqf = legacy ? DQF_MUTABLE : 0;
if (dqai.dqai_concurrent) {
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
vtable = DISPATCH_VTABLE(queue_serial);
}
// 开始初始化, 申请空间
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s));
// 初始化值
_dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
(dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
// 设置入参
dq->dq_label = label;
dq->dq_priority = _dispatch_priority_make((dispatch_qos_t)dqai.dqai_qos,
dqai.dqai_relpri);
// 后面涉及两个函数,暂时没研究透,先省略
_dispatch_retain(tq);
dq->do_targetq = tq;
_dispatch_object_debug(dq, "%s", __func__);
return _dispatch_trace_queue_create(dq)._dq;
}