美文网首页
GCD源码分析(上)

GCD源码分析(上)

作者: 默默_David | 来源:发表于2020-06-11 18:39 被阅读0次

    GCD源码官网下载地址

    GCD的源码在我看来,一直是iOS源码中最晦涩难懂一种,因为涉及到太多的宏定义和结构定义,并且没有多少关于GCD源码的文章作为参考,我只能根据自己的理解来粗略进行分析,如果有哪些错误或者不足之处,希望以后看到本篇文章的大佬能够留言指出,谢谢!

    一. 从打印开始

    我们先来看一段常写代码,并分析其属性

    - (void)testQueue{
        dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
        NSLog(@"serialQueue:%@",serialQueue);
        
        dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
        NSLog(@"concurrentQueue:%@",concurrentQueue);
        
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        NSLog(@"mainQueue:%@",mainQueue);
        
        dispatch_queue_t default_globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        NSLog(@"default_globalQueue:%@",default_globalQueue);
        
        dispatch_queue_t low_globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
        NSLog(@"low_globalQueue:%@",low_globalQueue);
        
        dispatch_queue_t high_globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
        NSLog(@"high_globalQueue:%@",high_globalQueue);
    }
    打印结果
    serialQueue:<OS_dispatch_queue_serial: serialQueue>
    concurrentQueue:<OS_dispatch_queue_concurrent: concurrentQueue>
    mainQueue:<OS_dispatch_queue_main: com.apple.main-thread>
    default_globalQueue:<OS_dispatch_queue_global: com.apple.root.default-qos>
    low_globalQueue:<OS_dispatch_queue_global: com.apple.root.utility-qos>
    high_globalQueue:<OS_dispatch_queue_global: com.apple.root.user-initiated-qos>
    

    我们在将断点加在最后,po一下具体的内部属性


    po结果.png

    我们知道,主队列也是串行队列,全局队列也是并行队列,从po出的信息来看他们的共性

    • 主队列和串行队列的width0x1,而并行队列的width都大于1
    • 全局队列的target都是[0x0],串行队列的target都显示的是com.apple.root.default-qos.overcommit[0x103021f80],并行队列的target为com.apple.root.default-qos[0x103021f00]

    据此,我们可以初步得出结论:

    1. 串行队列的宽度(width)为1,并行队列的宽度大于1
    2. 全局队列的target为[0x0],其他队列的target以com.apple.root.default-开头
    3. 自己创建的串行队列和并行队列都使用自己创建时给的名字,而主队列和全局队列,都有一个系统给的名字,主队列名为com.apple.main-thread,全局默认优先级名为com.apple.root.default-qos,全局低优先级名为com.apple.root.utility-qos,全局高优先级名为com.apple.root.user-initiated-qos

    接下来我们从源码开始分析

    二、从队列创建开始

    我们从dispatch_queue_create函数作为切入开始查询源码

    dispatch_queue_t
    dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
    {
       //调用_dispatch_lane_create_with_target
        return _dispatch_lane_create_with_target(label, attr,
                DISPATCH_TARGET_QUEUE_DEFAULT, true);
    }
    
    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)
    {
        
        //1. 第一步 设置dispatch_queue_attr_info_t属性
        /*
         通过传入的队列属性,设置队列信息
         串行队列 返回的是空字典
         非串行队列 表示叫
        */
        dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
    
        /*
         规范化各个参数,如(qos, overcommit, tq)
         */
        dispatch_qos_t qos = dqai.dqai_qos;
    #if !HAVE_PTHREAD_WORKQUEUE_QOS
        //如果qos等于6,那么将值设置为5
        if (qos == DISPATCH_QOS_USER_INTERACTIVE) {
            dqai.dqai_qos = qos = DISPATCH_QOS_USER_INITIATED;
        }
        //如果qos等于1,那么将值设置为2
        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,
                    overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;
            if (unlikely(!tq)) {
                DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
            }
        }
    
        /*
         第2步,创建队列
         */
        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;
        //DQF_MUTABLE             = 0x00400000,
        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 {
            //这个是串行 生成名为OS_dispatch_queue_serial_class的类
            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));
        /*
         #define DISPATCH_QUEUE_WIDTH_FULL          0x1000ull 也就是4096
         #define DISPATCH_QUEUE_WIDTH_POOL (DISPATCH_QUEUE_WIDTH_FULL - 1) 0xfff 也就是4095
         #define DISPATCH_QUEUE_WIDTH_MAX  (DISPATCH_QUEUE_WIDTH_FULL - 2) 0xffe 也就是4094
         */
        //构造方法,初始化队列属性
        _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;
    }
    

    上面的源码多数地方已经给了注释,我们来捋一捋步骤:

    1. 通过传入的参数 配置队列属性

    dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
    

    我们来看看dispatch_queue_attr_info_t是个什么结构

    typedef uint32_t dispatch_qos_t;
    typedef uint32_t dispatch_priority_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;
        //1为并行,0位串行
        uint16_t dqai_concurrent:1;
        uint16_t dqai_inactive:1;
    } dispatch_queue_attr_info_t;
    

    这是一个很明显的位域结构,其他属性我们先不管,我们第一眼可以看到dqai_concurrent属性,占一位,取值在0和1之间,我们可以初步推断dqai_concurrent是用来标识队列是串行还是并行。

    接下来我们继续查看_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);
    
        //设置dispatch_queue_attr_info_t的各个属性值
        
        //对2进行取余
        dqai.dqai_inactive = (idx % DISPATCH_QUEUE_ATTR_INACTIVE_COUNT);
        //除以2,下降一位,接下来就好设置dqai_concurrent的值了
        idx /= DISPATCH_QUEUE_ATTR_INACTIVE_COUNT;
        
        //对2进行取余,然后再取反,得到1
        dqai.dqai_concurrent = !(idx % DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT);
        idx /= DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT;
    
        //对16取余
        dqai.dqai_relpri = -(int)(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;
    }
    

    这个函数里面具体操作如下:

    • 如果是串行队列,直接返回空
    • 如果是并行队列,则进行位操作,逐个设置位域内部值

    设置好队列属性初始值之后,我们接着来规范化各个参数

        /*
         规范化各个参数,如(qos, overcommit, tq)
         */
        dispatch_qos_t qos = dqai.dqai_qos;
    #if !HAVE_PTHREAD_WORKQUEUE_QOS
        //如果qos等于6,那么将值设置为5
        if (qos == DISPATCH_QOS_USER_INTERACTIVE) {
            dqai.dqai_qos = qos = DISPATCH_QOS_USER_INITIATED;
        }
        //如果qos等于1,那么将值设置为2
        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,
                    overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;
            if (unlikely(!tq)) {
                DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
            }
        }
    

    这个里面,先设置qos的值,而系统定义了多个宏来表示qos的值,我们可以看到实际的qos取值在0-6之间,0表示未确定,还有一个15表示饱和的,而且从这些宏定义的英语取名和我们之前的打印结果可以看出,qos就是关于优先级的值,而且还可以看出,高优先级的qos为5,低优先级的qos为3,默认优先级的qos为4,而后台优先级的qos为2,所以我们可以假定推断:后台优先级的优先级比低优先级还低

    typedef uint32_t dispatch_qos_t;
    
    #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)
    

    然后设置overcommit的值,从下面我们可以看到overcommit是一个枚举

    typedef enum {
       //不明确
        _dispatch_queue_attr_overcommit_unspecified = 0,
        //可以复用
        _dispatch_queue_attr_overcommit_enabled,
        //不可以复用
        _dispatch_queue_attr_overcommit_disabled,
    } _dispatch_queue_attr_overcommit_t;
    

    再接下来是设置tq的值,由于调用这个函数我们传入的tq为NULL,所以会进入这段代码

    if (!tq) {
        tq = _dispatch_get_root_queue(
        qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos,
        overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;
        if (unlikely(!tq)) {
            DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");}
        }
    

    这段代码调用了_dispatch_get_root_queue函数,传入两个参数,第一个参数传入的值,如果qos的值不为0,则传入qos的值,否则传入默认值4;第二个参数传入的0或者1,如果可复用则传入的为1,否则传入0

    DISPATCH_ALWAYS_INLINE DISPATCH_CONST
    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];
    }
    

    我们关注返回值&_dispatch_root_queues[2 * (qos - 1) + overcommit];,这句的意思是从一个叫_dispatch_root_queues的数组中取出值,赋值给tq
    我们来看看这个数组是什么:

    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,
        ),
    };
    

    我们可以看出这个数组一共定义了12个成员,取得它们其中某一个,然后取地址,就是我们的tq的值。而下标2 * (qos - 1) + overcommit就是根据我们传入的值计算得来,按照默认传入的default来看,就是2*3+0/1,也就是6或者7,我们可以看到下标为6的队列名为"com.apple.root.default-qos",和我们在外面打印出来的默认优先级的全局队列一致
    从这里我们大致可以猜想:
    默认创建了12个静态队列,包含了全局队列,我们获取全局队列的时候,是直接在数组中读取的

    2. 创建队列

        /*
         第2步,创建队列
         */
        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;
        //DQF_MUTABLE             = 0x00400000,
        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 {
            //这个是串行 生成名为OS_dispatch_queue_serial_class的类
            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));
        /*
         #define DISPATCH_QUEUE_WIDTH_FULL          0x1000ull 也就是4096
         #define DISPATCH_QUEUE_WIDTH_POOL (DISPATCH_QUEUE_WIDTH_FULL - 1) 0xfff 也就是4095
         #define DISPATCH_QUEUE_WIDTH_MAX  (DISPATCH_QUEUE_WIDTH_FULL - 2) 0xffe 也就是4094
         */
        //构造方法,初始化队列属性
        _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__);
    

    一开始是设置并行/串行的队列类名,使用DISPATCH_VTABLE来设置,我们可以看出

    • 串行队列类名以OS_dispatch_queue_serial开头
    • 并行队列类名以OS_dispatch_queue_concurrent开头

    这和我们一开始打印出来的类名一致

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

    接下来是设置队列名label

    if (label) {
            const char *tmp = _dispatch_strdup_if_mutable(label);
            if (tmp != label) {
                dqf |= DQF_LABEL_NEEDS_FREE;
                label = tmp;
            }
    }
    

    接着根据设置好的类名,分配内存,生成queue,我们也可以看到dispatch_lane_t结构体的结构,这一步我们暂不做深究,以后研究更多了来补上

    //开辟内存 - 生成响应的对象 queue
        dispatch_lane_t dq = _dispatch_object_alloc(vtable,
                sizeof(struct dispatch_lane_s));
    
    #define DISPATCH_LANE_CLASS_HEADER(x) \
        struct dispatch_queue_s _as_dq[0]; \
        DISPATCH_QUEUE_CLASS_HEADER(x, \
                struct dispatch_object_s *volatile dq_items_tail); \
        dispatch_unfair_lock_s dq_sidelock; \
        struct dispatch_object_s *volatile dq_items_head; \
        uint32_t dq_side_suspend_cnt
    
    typedef struct dispatch_lane_s {
        DISPATCH_LANE_CLASS_HEADER(lane);
        /* 32bit hole on LP64 */
    } DISPATCH_ATOMIC64_ALIGN *dispatch_lane_t;
    
    #define DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__) \
        _DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__); \
        /* LP64 global queue cacheline boundary */ \
        unsigned long dq_serialnum; \
        const char *dq_label; \
        DISPATCH_UNION_LE(uint32_t volatile dq_atomic_flags, \
            const uint16_t dq_width, \
            const uint16_t __dq_opaque2 \
        ); \
        dispatch_priority_t dq_priority; \
        union { \
            struct dispatch_queue_specific_head_s *dq_specific_head; \
            struct dispatch_source_refs_s *ds_refs; \
            struct dispatch_timer_source_refs_s *ds_timer_refs; \
            struct dispatch_mach_recv_refs_s *dm_recv_refs; \
            struct dispatch_channel_callbacks_s const *dch_callbacks; \
        }; \
        int volatile dq_sref_cnt
    
    struct dispatch_queue_s {
        DISPATCH_QUEUE_CLASS_HEADER(queue, void *__dq_opaque1);
        /* 32bit hole on LP64 */
    } DISPATCH_ATOMIC64_ALIGN;
    

    然后我们调用构造方法,对队列进行初始化

        /*
         #define DISPATCH_QUEUE_WIDTH_FULL          0x1000ull 也就是4096
         #define DISPATCH_QUEUE_WIDTH_POOL (DISPATCH_QUEUE_WIDTH_FULL - 1) 0xfff 也就是4095
         #define DISPATCH_QUEUE_WIDTH_MAX  (DISPATCH_QUEUE_WIDTH_FULL - 2) 0xffe 也就是4094
         */
        //构造方法,初始化队列属性
        _dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
                DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
                (dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
    

    从这段代码我们可以看出,我们自己创建的串行队列的width为1,自己创建的并行队列width为0xffe,也就是(0x1000-0x2),这也和我们之前打印出来的一致

    接下是设置队列标签(名字),设置队列优先级等,然后调用_dispatch_retain(tq);将队列的引用计数加1

    _dispatch_retain(tq);
    

    最后调用_dispatch_trace_queue_create(dq)._dq来返回创建的队列

    我们看到_dispatch_trace_queue_create调用了_dispatch_introspection_queue_create,然后_dispatch_introspection_queue_create又调用了_dispatch_introspection_queue_create最后return upcast(dq)._dqu;dq强转为根父类dispatch_object_t返回其_dqu值,这就是我们创建的queue

    DISPATCH_ALWAYS_INLINE
    static inline dispatch_queue_class_t
    _dispatch_trace_queue_create(dispatch_queue_class_t dqu)
    {
        _dispatch_only_if_ktrace_enabled({
            uint64_t dq_label[4] = {0}; // So that we get the right null termination
            dispatch_queue_t dq = dqu._dq;
            strncpy((char *)dq_label, (char *)dq->dq_label ?: "", sizeof(dq_label));
    
            _dispatch_ktrace2(DISPATCH_QOS_TRACE_queue_creation_start,
                    dq->dq_serialnum,
                    _dispatch_priority_to_pp_prefer_fallback(dq->dq_priority));
    
            _dispatch_ktrace4(DISPATCH_QOS_TRACE_queue_creation_end,
                            dq_label[0], dq_label[1], dq_label[2], dq_label[3]);
        });
    
        return _dispatch_introspection_queue_create(dqu);
    }
    

    再看_dispatch_introspection_queue_create函数的实现

    dispatch_queue_class_t
    _dispatch_introspection_queue_create(dispatch_queue_t dq)
    {
        dispatch_queue_introspection_context_t dqic;
        size_t sz = sizeof(struct dispatch_queue_introspection_context_s);
    
        if (!_dispatch_introspection.debug_queue_inversions) {
            sz = offsetof(struct dispatch_queue_introspection_context_s,
                    __dqic_no_queue_inversion);
        }
        dqic = _dispatch_calloc(1, sz);
        dqic->dqic_queue._dq = dq;
        if (_dispatch_introspection.debug_queue_inversions) {
            LIST_INIT(&dqic->dqic_order_top_head);
            LIST_INIT(&dqic->dqic_order_bottom_head);
        }
        dq->do_finalizer = dqic;
    
        _dispatch_unfair_lock_lock(&_dispatch_introspection.queues_lock);
        LIST_INSERT_HEAD(&_dispatch_introspection.queues, dqic, dqic_list);
        _dispatch_unfair_lock_unlock(&_dispatch_introspection.queues_lock);
    
        DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_create, dq);
        if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_create)) {
            _dispatch_introspection_queue_create_hook(dq);
        }
        //强转为dispatch_object_t类型 然后返回
        return upcast(dq)._dqu;
    }
    

    最后我们来看一看dispatch_object_tdispatch_queue_class_t的结构

    typedef struct dispatch_object_s {
    private:
        dispatch_object_s();
        ~dispatch_object_s();
        dispatch_object_s(const dispatch_object_s &);
        void operator=(const dispatch_object_s &);
    } *dispatch_object_t;
    
    typedef union {
        struct dispatch_queue_s *_dq;
        struct dispatch_workloop_s *_dwl;
        struct dispatch_lane_s *_dl;
        struct dispatch_queue_static_s *_dsq;
        struct dispatch_queue_global_s *_dgq;
        struct dispatch_queue_pthread_root_s *_dpq;
        struct dispatch_source_s *_ds;
        struct dispatch_channel_s *_dch;
        struct dispatch_mach_s *_dm;
        dispatch_lane_class_t _dlu;
    #ifdef __OBJC__
        id<OS_dispatch_queue> _objc_dq;
    #endif
    } dispatch_queue_class_t DISPATCH_TRANSPARENT_UNION;
    

    三、主队列

    我们从dispatch_get_main_queue()入手

    DISPATCH_INLINE DISPATCH_ALWAYS_INLINE DISPATCH_CONST DISPATCH_NOTHROW
    dispatch_queue_main_t
    dispatch_get_main_queue(void)
    {
        return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
    }
    

    源码中调用了DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);,我们先看看DISPATCH_GLOBAL_OBJECT是什么东西

    #define DISPATCH_GLOBAL_OBJECT(type, object) ((OS_OBJECT_BRIDGE type)&(object))
    

    然后我们再看看两个参数,我们先看看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_t

    我们再看第二个参数_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,
    };
    

    这个结构体设置了主线程的各个属性,从结构体中我们可以看到dq_label = "com.apple.main-thread",这表示是我们的主线程,这也和我们的打印一致

    四、全局队列

    我们也从dispatch_get_global_queue函数出发

    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_root_queue函数

    DISPATCH_ALWAYS_INLINE DISPATCH_CONST
    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];
    }
    

    在第二段创建队列中我们可以看到,_dispatch_get_root_queue函数的返回值是从_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数组中取出预先写好的队列来返回。

    而从.dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL)这句中可以看到,全局队列的宽度为0xfff,宽度大于1,说明全局队列是一个并发队列,由前面可知,我们自己创建的并行队列宽度为0xffe,这就是全局队列和自创的并发队列的区别

    相关文章

      网友评论

          本文标题:GCD源码分析(上)

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