美文网首页
GCD源码解析(一)-dispatch_queue_create

GCD源码解析(一)-dispatch_queue_create

作者: king_jensen | 来源:发表于2019-04-05 15:39 被阅读0次

    阅读GCD源码,首先需要下载libdispatch源码。很多同学拿到源码就直接埋头苦干,我觉得这样会像无头苍蝇一样没有重点,容易懵逼,效率低。相比objc,CFRunloop源码而言,libdispatch源码难度比较高。libdispatch源码中使用了很多宏、且名字特别长、嵌套深、还包含很多os开头的函数,所以阅读起来不是那么容易。
    本文以问题的形式来窥探源码,这种方式比较有重点,效率高。

    使用GCD的队列需从创建队列开始,因此我们源码分析也从队列的创建开始分析。

     dispatch_queue_create("jensen.cn", NULL);
    

    对于队列的创建,我们先探索如下2个问题:
    1.队列是如何产生的?
    2.串行队列与并行队列有什么区别?

    带着这两个问题,我们打开源码找到dispatch_queue_create函数:

    #define DISPATCH_TARGET_QUEUE_DEFAULT NULL
    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_queue_create函数的attr一般传入DISPATCH_QUEUE_SERIALDISPATCH_QUEUE_CONCURRENT或者nil,而宏定义DISPATCH_TARGET_QUEUE_DEFAULT其实就是null
    进入_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)
    {
           //通过当前的属性获取属性信息
        dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
    
        // Step 1: Normalize arguments (qos, overcommit, tq)
        //
        dispatch_qos_t qos = dqai.dqai_qos;
    #if !HAVE_PTHREAD_WORKQUEUE_QOS
        if (qos == DISPATCH_QOS_USER_INTERACTIVE) {
            dqai.dqai_qos = qos = DISPATCH_QOS_USER_INITIATED;
        }
        if (qos == DISPATCH_QOS_MAINTENANCE) {
            dqai.dqai_qos = qos = DISPATCH_QOS_BACKGROUND;
        }
    #endif // !HAVE_PTHREAD_WORKQUEUE_QOS
    
        _dispatch_queue_attr_overcommit_t overcommit = dqai.dqai_overcommit;
        if (overcommit != _dispatch_queue_attr_overcommit_unspecified && tq) {
            if (tq->do_targetq) {
                DISPATCH_CLIENT_CRASH(tq, "Cannot specify both overcommit and "
                        "a non-global target queue");
            }
        }
    
        if (tq && dx_type(tq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE) {
            // Handle discrepancies between attr and target queue, attributes win
            if (overcommit == _dispatch_queue_attr_overcommit_unspecified) {
                if (tq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) {
                    overcommit = _dispatch_queue_attr_overcommit_enabled;
                } else {
                    overcommit = _dispatch_queue_attr_overcommit_disabled;
                }
            }
            if (qos == DISPATCH_QOS_UNSPECIFIED) {
                qos = _dispatch_priority_qos(tq->dq_priority);
            }
            tq = NULL;
        } else if (tq && !tq->do_targetq) {
            // target is a pthread or runloop root queue, setting QoS or overcommit
            // is disallowed
            if (overcommit != _dispatch_queue_attr_overcommit_unspecified) {
                DISPATCH_CLIENT_CRASH(tq, "Cannot specify an overcommit attribute "
                        "and use this kind of target queue");
            }
        } else {
            if (overcommit == _dispatch_queue_attr_overcommit_unspecified) {
                // Serial queues default to overcommit!
                overcommit = dqai.dqai_concurrent ?
                        _dispatch_queue_attr_overcommit_disabled :
                        _dispatch_queue_attr_overcommit_enabled;
            }
        }
        if (!tq) {
            tq = _dispatch_get_root_queue(
                    qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, // 4
                    overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq; // 0 1
            if (unlikely(!tq)) {
                DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
            }
        }
    
        //
        // Step 2: Initialize the queue
        //
    
        if (legacy) {
            // if any of these attributes is specified, use non legacy classes
            if (dqai.dqai_inactive || dqai.dqai_autorelease_frequency) {
                legacy = false;
            }
        }
    
        const void *vtable;
        dispatch_queue_flags_t dqf = legacy ? DQF_MUTABLE : 0;
        if (dqai.dqai_concurrent) {
            // 通过dqai.dqai_concurrent 来区分并发和串行
            // OS_dispatch_queue_concurrent_class
            vtable = DISPATCH_VTABLE(queue_concurrent);
        } else {
            vtable = DISPATCH_VTABLE(queue_serial);
        }
        switch (dqai.dqai_autorelease_frequency) {
        case DISPATCH_AUTORELEASE_FREQUENCY_NEVER:
            dqf |= DQF_AUTORELEASE_NEVER;
            break;
        case DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM:
            dqf |= DQF_AUTORELEASE_ALWAYS;
            break;
        }
        if (label) {
            const char *tmp = _dispatch_strdup_if_mutable(label);
            if (tmp != label) {
                dqf |= DQF_LABEL_NEEDS_FREE;
                label = tmp;
            }
        }
    
        // 开辟内存 - 生成响应的对象 queue
        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);
        if (overcommit == _dispatch_queue_attr_overcommit_enabled) {
            dq->dq_priority |= DISPATCH_PRIORITY_FLAG_OVERCOMMIT;
        }
        if (!dqai.dqai_inactive) {
            _dispatch_queue_priority_inherit_from_target(dq, tq);
            _dispatch_lane_inherit_wlh_from_target(dq, tq);
        }
        _dispatch_retain(tq);
        dq->do_targetq = tq;
        _dispatch_object_debug(dq, "%s", __func__);
        return _dispatch_trace_queue_create(dq)._dq;
    
    }
    

    代码中首先通过外部传入的dqa属性获取属性信息dqai。进入获取属性信息的函数_dispatch_queue_attr_to_info

    dispatch_queue_attr_info_t
    _dispatch_queue_attr_to_info(dispatch_queue_attr_t dqa)
    {
        dispatch_queue_attr_info_t dqai = { };
    
          //串行队列,返回空
        if (!dqa) return dqai;
    
    #if DISPATCH_VARIANT_STATIC
        if (dqa == &_dispatch_queue_attr_concurrent) {
            dqai.dqai_concurrent = true;
            return dqai;
        }
    #endif
    
        if (dqa < _dispatch_queue_attrs ||
                dqa >= &_dispatch_queue_attrs[DISPATCH_QUEUE_ATTR_COUNT]) {
            DISPATCH_CLIENT_CRASH(dqa->do_vtable, "Invalid queue attribute");
        }
    
        // 苹果的算法
        size_t idx = (size_t)(dqa - _dispatch_queue_attrs);
    
        // 位域写法  通过idx不断的获取对应的值通过取余
        // 0000 000000000 00000000000 0000 000  1
           //通过位数来区分
    
          dqai.dqai_inactive = (idx % DISPATCH_QUEUE_ATTR_INACTIVE_COUNT);
        idx /= DISPATCH_QUEUE_ATTR_INACTIVE_COUNT;
    
        dqai.dqai_concurrent = !(idx % DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT);
        idx /= DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT;
    
        dqai.dqai_relpri = -(idx % DISPATCH_QUEUE_ATTR_PRIO_COUNT);
        idx /= DISPATCH_QUEUE_ATTR_PRIO_COUNT;
    
        dqai.dqai_qos = idx % DISPATCH_QUEUE_ATTR_QOS_COUNT;
        idx /= DISPATCH_QUEUE_ATTR_QOS_COUNT;
    
        dqai.dqai_autorelease_frequency =
                idx % DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT;
        idx /= DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT;
    
        dqai.dqai_overcommit = idx % DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT;
        idx /= DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT;
    
        return dqai;
    }
    
    

    如果是参数dqa为NULL,_dispatch_queue_attr_to_info函数直接返回dispatch_queue_attr_info_t类型的空结构体。如果不是NULL,苹果将通过规定的算法计算出idx,idx采用了位域写法,通过取余方式获取对应的值,为dqa初始化。
    dispatch_queue_attr_info_t类型如下

    typedef struct dispatch_queue_attr_info_s {
        dispatch_qos_t dqai_qos : 8;
        int      dqai_relpri : 8;
        uint16_t dqai_overcommit:2;
        uint16_t dqai_autorelease_frequency:2;
        uint16_t dqai_concurrent:1;
        uint16_t dqai_inactive:1;
    } dispatch_queue_attr_info_t;
    

    继续阅读_dispatch_lane_create_with_target函数,我们发现并行和串行是通过dqai.diqi_concurrent来区分并行队列和串行队列的。

    if (dqai.dqai_concurrent) {
            // 通过dqai.dqai_concurrent 来区分并发和串行
            // OS_dispatch_queue_concurrent_class
            vtable = DISPATCH_VTABLE(queue_concurrent);
        } else {
            vtable = DISPATCH_VTABLE(queue_serial);
        }
    

    查看代码中DISPATCH_VTABLE的定义:

    #define DISPATCH_VTABLE(name) DISPATCH_OBJC_CLASS(name)
    #define DISPATCH_OBJC_CLASS(name)   (&DISPATCH_CLASS_SYMBOL(name))
    #if USE_OBJC
    #define DISPATCH_CLASS_SYMBOL(name) OS_dispatch_##name##_class
    

    OS_dispatch_##name##_class,底层将传入的参数name,拼接生成对应的队列类,
    串行队列的类为: OS_dispatch_queue_serial_class,并行队列的类为:OS_dispatch_queue_concurrent_class

        if (label) {
            const char *tmp = _dispatch_strdup_if_mutable(label);
            if (tmp != label) {
                dqf |= DQF_LABEL_NEEDS_FREE;
                label = tmp;
            }
        }
        // 开辟内存 - 生成响应的对象 queue
        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);
        if (overcommit == _dispatch_queue_attr_overcommit_enabled) {
            dq->dq_priority |= DISPATCH_PRIORITY_FLAG_OVERCOMMIT;
        }
        if (!dqai.dqai_inactive) {
            _dispatch_queue_priority_inherit_from_target(dq, tq);
            _dispatch_lane_inherit_wlh_from_target(dq, tq);
        }
        _dispatch_retain(tq);
        dq->do_targetq = tq;
    

    判断参数label如果不为NULL,调用函数_dispatch_strdup_if_mutable(const char *str)进行处理,判断如果源字符串是可变的,就重新分配内存并拷贝内容到内存中。否则直接返回。

    const char *
    _dispatch_strdup_if_mutable(const char *str)
    {
    #if HAVE_DYLD_IS_MEMORY_IMMUTABLE
        size_t size = strlen(str) + 1;
        if (unlikely(!_dyld_is_memory_immutable(str, size))) {
            char *clone = (char *) malloc(size);
            if (dispatch_assume(clone)) {
                memcpy(clone, str, size);
            }
            return clone;
        }
        return str;
    #else
        return strdup(str);
    #endif
    }
    

    处理完成后,判断是否是原来的那一个label,不一致就替换。
    接下来调用_dispatch_object_alloc函数为队列分配内存,生成响应的对象dq,将队列包装成dispatch_lane_t类型。
    然后调用_dispatch_queue_init构造函数,为队列初始化。构造方法的参数width

    #define DISPATCH_QUEUE_WIDTH_FULL           0x1000ull
    #define DISPATCH_QUEUE_WIDTH_MAX (DISPATCH_QUEUE_WIDTH_FULL - 2)
        // 构造方法
        _dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
                DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
                (dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
    

    通过dqai.dqai_concurrent判断,如果是并行队列,width0xffe,十进制为4094,如果是串行队列则width为1,通过这里我们也就知道为什么并行队列口子大,串行队列口子小。
    再为dq的所有属性赋值,dq_labeldq_priority等等。
    将自己创建的队列绑定到root队列上。

    我们注意到在_dispatch_lane_create_with_target函数在最后调用了_dispatch_trace_queue_create函数,在_dispatch_trace_queue_create函数中调用_dispatch_introspection_queue_create函数,在_dispatch_introspection_queue_create中调用_dispatch_introspection_queue_create_hook函数,在_dispatch_introspection_queue_create_hook函数调用dispatch_introspection_queue_get_info函数。

    #define dx_vtable(x) (&(x)->do_vtable->_os_obj_vtable)
    #define dx_metatype(x) (dx_vtable(x)->do_type & _DISPATCH_META_TYPE_MASK)
    DISPATCH_USED inline
    dispatch_introspection_queue_s
    dispatch_introspection_queue_get_info(dispatch_queue_t dq)
    {
        if (dx_metatype(dq) == _DISPATCH_WORKLOOP_TYPE) {
            return _dispatch_introspection_workloop_get_info(upcast(dq)._dwl);
        }
        return _dispatch_introspection_lane_get_info(upcast(dq)._dl);
    }
    

    通过dx_metatype判断是否为并发队列,如果为串行队列则调用_dispatch_introspection_workloop_get_info函数,否则调用_dispatch_introspection_lane_get_info函数。

    static inline dispatch_introspection_queue_s
    _dispatch_introspection_workloop_get_info(dispatch_workloop_t dwl)
    {
        uint64_t dq_state = os_atomic_load2o(dwl, dq_state, relaxed);
    
        dispatch_introspection_queue_s diq = {
            .queue = dwl->_as_dq,
            .target_queue = dwl->do_targetq,
            .label = dwl->dq_label,
            .serialnum = dwl->dq_serialnum,
            .width = 1,
            .suspend_count = 0,
            .enqueued = _dq_state_is_enqueued(dq_state),
            .barrier = _dq_state_is_in_barrier(dq_state),
            .draining = 0,
            .global = 0,
            .main = 0,
        };
        return diq;
    }
    
    static inline dispatch_introspection_queue_s
    _dispatch_introspection_lane_get_info(dispatch_lane_class_t dqu)
    {
        dispatch_lane_t dq = dqu._dl;
        bool global = _dispatch_object_is_global(dq);
        uint64_t dq_state = os_atomic_load2o(dq, dq_state, relaxed);
    
        dispatch_introspection_queue_s diq = {
            .queue = dq->_as_dq,
            .target_queue = dq->do_targetq,
            .label = dq->dq_label,
            .serialnum = dq->dq_serialnum,
            .width = dq->dq_width,
            .suspend_count = _dq_state_suspend_cnt(dq_state) + dq->dq_side_suspend_cnt,
            .enqueued = _dq_state_is_enqueued(dq_state) && !global,
            .barrier = _dq_state_is_in_barrier(dq_state) && !global,
            .draining = (dq->dq_items_head == (void*)~0ul) ||
                    (!dq->dq_items_head && dq->dq_items_tail),
            .global = global,
            .main = dx_type(dq) == DISPATCH_QUEUE_MAIN_TYPE,
        };
        return diq;
    }
    

    函数中将传入的队列用dispatch_introspection_queue_s这个类型重新包装,重新赋值。

    typedef struct dispatch_introspection_queue_s {
        dispatch_queue_t queue;
        dispatch_queue_t target_queue;
        const char *label;
        unsigned long serialnum;
        unsigned int width;
        unsigned int suspend_count;
        unsigned long enqueued:1,
                barrier:1,
                draining:1,
                global:1,
                main:1;
    } dispatch_introspection_queue_s;
    

    至此,我们已经了解队列创建的整个过程,以及代码中是如何区别串行队列和并行队列。下面我们来验证一下:

      dispatch_queue_t queueSer = dispatch_queue_create("com.jensen.ser", NULL);
        dispatch_queue_t queueCon = dispatch_queue_create("com.jensen.con", DISPATCH_QUEUE_CONCURRENT);
    

    通过lldb,我们分别打印queueSer和queueCon队列:


    7C8B2DEC5F3093B133073C7A861CF8E7.png

    打印结果中,我们看到串行队列和并行队列的类分别是OS_dispatch_queue_serialOS_dispatch_queue_concurrent,label分别是调用时传入的参数com.jensen.sercom.jensen.con,width分别为0x10xffe,与我们代码分析的结果一致。

    但是我们还是有疑问,串行队列和并行队列的target分别为com.apple.root.default-qos.overcommitcom.apple.root.default-qos,这个是如何区别并关联的呢?带着这个问题我们继续分析。
    其实这个target跟我们上述提到的,将自己创建的队列绑定到root队列有关系。

    dq->do_targetq = tq;
    

    那么我们要弄清楚target, 那么就必须从获取root队列的函数入手。

    #define DISPATCH_QOS_UNSPECIFIED        ((dispatch_qos_t)0)
    #define DISPATCH_QOS_MAINTENANCE        ((dispatch_qos_t)1)
    #define DISPATCH_QOS_BACKGROUND         ((dispatch_qos_t)2)
    #define DISPATCH_QOS_UTILITY            ((dispatch_qos_t)3)
    #define DISPATCH_QOS_DEFAULT            ((dispatch_qos_t)4)
    #define DISPATCH_QOS_USER_INITIATED     ((dispatch_qos_t)5)
    #define DISPATCH_QOS_USER_INTERACTIVE   ((dispatch_qos_t)6)
    #define DISPATCH_QOS_MIN                DISPATCH_QOS_MAINTENANCE
    #define DISPATCH_QOS_MAX                DISPATCH_QOS_USER_INTERACTIVE
    #define DISPATCH_QOS_SATURATED          ((dispatch_qos_t)15)
    
    if (!tq) {
            tq = _dispatch_get_root_queue(
                    qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, // 4
                    overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq; // 0 1
            if (unlikely(!tq)) {
                DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
            }
        }
    

    往上查看发现dispatch_qos_t qos = dqai.dqai_qos 代码, 那么我们得出当队列是串行队列qosDISPATCH_QOS_UNSPECIFIED_dispatch_get_root_queue函数传入的第一个参数为DISPATCH_QOS_DEFAULT,否则为qos本身。第二个参数为overcommit == _dispatch_queue_attr_overcommit_enabled,是一个bool,要那么是0,要么是1。跟进_dispatch_get_root_queue函数:

    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");
        }
        // 4-1= 3
        // 2*3+0/1 = 6/7
        return &_dispatch_root_queues[2 * (qos - 1) + overcommit];
    }
    

    当为串行队列时,qos4,overcommit0/1,2 * (qos - 1) + overcommit 的下标为2*(4-1)+0/1 = 6/7.

    我们找到dispatch_root_queues数组的初始化如下:

    struct dispatch_queue_global_s _dispatch_root_queues[] = {
    #define _DISPATCH_ROOT_QUEUE_IDX(n, flags) \
            ((flags & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) ? \
            DISPATCH_ROOT_QUEUE_IDX_##n##_QOS_OVERCOMMIT : \
            DISPATCH_ROOT_QUEUE_IDX_##n##_QOS)
    #define _DISPATCH_ROOT_QUEUE_ENTRY(n, flags, ...) \
        [_DISPATCH_ROOT_QUEUE_IDX(n, flags)] = { \
            DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), \
            .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, \
            .do_ctxt = _dispatch_root_queue_ctxt(_DISPATCH_ROOT_QUEUE_IDX(n, flags)), \
            .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), \
            .dq_priority = flags | ((flags & DISPATCH_PRIORITY_FLAG_FALLBACK) ? \
                    _dispatch_priority_make_fallback(DISPATCH_QOS_##n) : \
                    _dispatch_priority_make(DISPATCH_QOS_##n, 0)), \
            __VA_ARGS__ \
        }
        _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_root_queues静态数组的初始化,我们知道target queue其实 是一些已经确定的值。那么上述得出的下标6/7,在dispatch_root_queues静态数组可查到target queuelabelcom.apple.root.default-qos或者com.apple.root.default-qos.overcommit

    我们已经了解队列创建时,root target是如何关联的了。我们联想到系统默认帮我们创建的主队列dispatch_get_main_queue()和全局并发队列dispatch_get_global_queue(0, 0)又是怎么样的呢?
    带着问题,我们先通过lldb打印主队列信息和全局队列的信息。

        dispatch_queue_t queueMain = dispatch_get_main_queue();
        dispatch_queue_t queueglob = dispatch_get_global_queue(0, 0);
    
    662096559D60EB2E5851D5605C8222AA.png

    进入dispatch_get_main_queue()dispatch_get_main_queue()源码,

    #define DISPATCH_GLOBAL_OBJECT(type, object) ((OS_OBJECT_BRIDGE type)&(object))
    
    dispatch_queue_main_t
    dispatch_get_main_queue(void)
    {
        return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
    }
    

    dispatch_queue_main_tdispatch_queue_static_s类型的结构体指针。

    typedef struct dispatch_queue_static_s *dispatch_queue_main_t;
    

    我们可以查看dispatch_queue_main_t如何创建的

    DISPATCH_DECL_SUBCLASS(dispatch_queue_main, dispatch_queue_serial);
    #define DISPATCH_DECL_SUBCLASS(name, base) OS_OBJECT_DECL_SUBCLASS(name, base)
    #define OS_OBJECT_DECL_SUBCLASS(name, super) \
            OS_OBJECT_DECL_IMPL(name, <OS_OBJECT_CLASS(super)>) 
    #define OS_OBJECT_DECL_IMPL(name, ...) \
            OS_OBJECT_DECL_PROTOCOL(name, __VA_ARGS__) \
            typedef NSObject<OS_OBJECT_CLASS(name)> \
                    * OS_OBJC_INDEPENDENT_CLASS name##_t
    
    

    从上述得知,dispatch_queue_main是继承dispatch_queue_serial, 并重写dispatch_queue_serial的函数。这就追溯到我们最开始的串行队列创建。
    这里传入dispatch_queue_main,所以主队列的底层类就是OS_dispatch_queue_main_class,与我们的打印也是一致的。
    _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_main_q的初始化中,我们可以看到主队列的labelcom.apple.main-thread,这就可以说明为什么主队列的labelcom.apple.main-thread
    上述代码中可以看到主队列的targetq_dispatch_get_default_queue(true),

    #define _dispatch_get_default_queue(overcommit) \
            _dispatch_root_queues[DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS + \
                    !!(overcommit)]._as_dq
    
    

    可以看到主队列的target是直接从静态数组_dispatch_root_\queues取值的。

    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_QUEUE_IDX_DEFAULT_QOS6,因此下标为7,查找静态数组得知下标为7target的``label为com.apple.root.default-qos.overcommit,与我们例子打印出的一致。
    我们已经弄清楚了主队列是怎么回事了。接下来我们继续分析全局队列dispatch_get_global_queue(0, 0)

    dispatch_queue_global_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_global_queue(long priority, unsigned long flags)函数中调用_dispatch_qos_from_queue_priority(long priority),通过priority获取qos

    #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
    #define DISPATCH_QOS_DEFAULT            ((dispatch_qos_t)4)
    DISPATCH_ALWAYS_INLINE
    static inline dispatch_qos_t
    _dispatch_qos_from_queue_priority(long priority)
    {
        switch (priority) {
        case DISPATCH_QUEUE_PRIORITY_BACKGROUND:      return DISPATCH_QOS_BACKGROUND;
        case DISPATCH_QUEUE_PRIORITY_NON_INTERACTIVE: return DISPATCH_QOS_UTILITY;
        case DISPATCH_QUEUE_PRIORITY_LOW:             return DISPATCH_QOS_UTILITY;
        case DISPATCH_QUEUE_PRIORITY_DEFAULT:         return DISPATCH_QOS_DEFAULT;
        case DISPATCH_QUEUE_PRIORITY_HIGH:            return DISPATCH_QOS_USER_INITIATED;
        default: return _dispatch_qos_from_qos_class((qos_class_t)priority);
        }
    }
    

    例子中输入的priority0,得出qos4.
    最后调用函数_dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit)直接获得队列。

    _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];
    }
    

    通过静态数组找到下标为6,就是全局并发队列的label

    #define DISPATCH_QUEUE_WIDTH_POOL (DISPATCH_QUEUE_WIDTH_FULL - 1)
    #define _DISPATCH_ROOT_QUEUE_ENTRY(n, flags, ...) \
        [_DISPATCH_ROOT_QUEUE_IDX(n, flags)] = { \
            DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), \
            .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, \
            .do_ctxt = _dispatch_root_queue_ctxt(_DISPATCH_ROOT_QUEUE_IDX(n, flags)), \
            .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), \
            .dq_priority = flags | ((flags & DISPATCH_PRIORITY_FLAG_FALLBACK) ? \
                    _dispatch_priority_make_fallback(DISPATCH_QOS_##n) : \
                    _dispatch_priority_make(DISPATCH_QOS_##n, 0)), \
            __VA_ARGS__ \
        }
    

    通过上述我们可以知道全局并发队列的widthDISPATCH_QUEUE_WIDTH_FULL - 1,0xfff,比我们自己创建的自定义队列0xffe1
    通过上述分析我们也总结出全局并发队列和自定义并发队列的区别在于:
    全局并发队列直接从静态数组中取出,而自定义全局队列需手动alloc,并关联root队列。全局并发队列width0xfff,而自定义并发队列的width0ffe

    总结:本文通过问题的方式简要探索gcd关于队列创建函数dispatch_queue_create(const char *_Nullable label, dispatch_queue_attr_t _Nullable attr),主队列dispatch_get_main_queue(void),全局并发队列dispatch_get_global_queue(long identifier, unsigned long flags)的源码。gcd源码难度较大,本位仅仅只是对一些要点进行指出。本文中可能存在说明不妥当的地方,希望大牛们多多指教!

    相关文章

      网友评论

          本文标题:GCD源码解析(一)-dispatch_queue_create

          本文链接:https://www.haomeiwen.com/subject/kgacbqtx.html