创立行列底层源码剖析

经过上篇文章 iOS 深化了解 GCD 函数和行列中,咱们了解函数和行列,知道行列的创立时经过 GCD 中的dispatch_queue_create办法,下面咱们在libdispatch.dylib(libdispatch-1173.60.1) 去探究行列是如何创立的(源码下载)

  • 查找 dispatch_queue_create
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
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 办法代码如下:

iOS GCD 底层源码剖析

【第二步】看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,验证如下
iOS GCD 底层源码剖析
  • 并发行列类型:OS_dispatch_queue_concurrent,验证如下
iOS GCD 底层源码剖析
#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 办法代码如下:

iOS GCD 底层源码剖析

_os_object_alloc_realized 办法代码如下:

iOS GCD 底层源码剖析
  • 进入_dispatch_queue_init办法,行列类型是dispatch_queue_t,并设置行列的相关特点。
iOS GCD 底层源码剖析

【第五步】经过_dispatch_trace_queue_create对创立的行列进行处理,其间_dispatch_trace_queue_create_dispatch_introspection_queue_create封装的宏界说,最后会回来处理过的_dq

iOS GCD 底层源码剖析

进入_dispatch_introspection_queue_create_hook -> dispatch_introspection_queue_get_info -> _dispatch_introspection_lane_get_info中可以看出,与咱们自界说的类仍是有所区别的,创立行列在底层的实现是经过模板创立的。

iOS GCD 底层源码剖析

总结

  • 行列创立办法dispatch_queue_create中的参数二(即行列类型), 决定了下层中 max & 1(用于区分是串行仍是并发), 其间1表明串行
  • queue也是一个目标,也需求经过底层 alloc + init 创立, 并且在 alloc 中也有一个class, 这个class是经过宏界说拼接而成,并且同时会指定isa的指向
  • 创立行列在底层的处理是经过模板创立的,其类型是dispatch_introspection_queue_s结构体。

dispatch_queue_create底层剖析流程如下图所示

iOS GCD 底层源码剖析