美文网首页
iOS---17----多线程之GCD

iOS---17----多线程之GCD

作者: 清风烈酒2157 | 来源:发表于2021-03-12 09:06 被阅读0次

    [TOC]

    GCD 简介

    • 什么是GCD?

    全称是 Grand Central Dispatch

    • C 语言,提供了非常多强大的函数 GCD的优势
    • GCD 是苹果公司为多核的并行运算提出的解决方案
    • GCD 会自动利用更多的CPU内核(比如双核、四核)
    • GCD 会自动管理线程的生命周期(创建线程、调度任务、销毁线程) 程序员只需要告诉 GCD 想要执行什么任务,不需要编写任何线程管理代码

    函数

    将任务添加到队列,并且指定执行任务的函数

    任务使用 block 封装

    • 任务的 block 没有参数也没有返回值
    • 执行任务的函数

    异步 dispatch_async

    • 不用等待当前语句执行完毕,就可以执行下一条语句 * 会开启线程执行 block的任务
    • 异步是多线程的代名词

    同步 dispatch_sync

    • 必须等待当前语句执行完毕,才会执行下一条语
    • 不会开启线程
    • 在当前执行 block 的任务

    外部block块 内部调用

    队列

    f0a09ae0e5400f93f6dd0cbc20cd6663
    afb29b47ad6ab1e3de0826038e11a2aa

    队列和函数

    140abcf0229f21455a45870eafd385e3

    死锁

    aa0e28c8974181fa4abbf3ac8d731819

    相关案例

    • 案例一

    互相等待

    a8caecc8c1918a37dffe8885e3ea7c45
    • 案例二

    互相等待

    ba739c2f513c45ba49770b36c9a4b0db
    • 案例三

    主线程内添加同步串行队列,互相等待堵塞线程

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            dispatch_sync(dispatch_get_main_queue(), ^(void){
                NSLog(@"这里死锁了");
            });
        }
        return 0;
    }
    

    案例四:

    dsipatch_apply嵌套使用也会死锁.

    dispatch_queue_t queue = dispatch_queue_create("me.tutuge.test.gcd", DISPATCH_QUEUE_SERIAL);
            
    dispatch_apply(3, queue, ^(size_t i) {
    NSLog(@"apply loop: %zu", i);
        
        //再来一个dispatch_apply!死锁!      
    dispatch_apply(3, queue, ^(size_t j) {
    NSLog(@"apply loop inside %zu", j);
    });
    });
    

    判断是否发生死锁的最好方法就是看有没有在串行队列(当然也包括主队列)中向这个队列添加任务。

    我们使用同步的方法编程,往往是要求保证任务之间的执行顺序是完全确定的。且不说GCD提供了很多强大的功能来满足这个需求,向串行队列中同步的添加任务本身就是不合理的,毕竟队列已经是串行的了,直接异步添加就可以了.

    底层探究

    串行队列和并发队列创建

    b944754d80770b7a69e50d833e10114a

    发现targetwidth的值是不一样的.

    队列是如果创建的

    1. 首先在libdispatch源码中找到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);
    }
    
    1. _dispatch_lane_create_with_target跟进去查看
    static dispatch_queue_t
    _dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
            dispatch_queue_t tq, bool legacy)
    {
            //其实就是把attr转化为{}字典形式的attr集合,dqai里面会有qos,overcommit,inactive,concurrent之类的key和value
        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;
    
            …… //设置QOS
    
        if (tq && dx_type(tq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE) {
            …… //tq为NULL所以不执行这段
        } else if (tq && !tq->do_targetq) {
            …… //tq为NULL所以不执行这段
        } else {
            if (overcommit == _dispatch_queue_attr_overcommit_unspecified) {
                // 串行queue默认overcommit,并行queue默认不overcommit
                overcommit = dqai.dqai_concurrent ?
                        _dispatch_queue_attr_overcommit_disabled :
                        _dispatch_queue_attr_overcommit_enabled;
            }
        }
        
        // 第一个参数 qos 为 4
        //第二个参数 overcommit 并发为0,串行为1 
        if (!tq) {
            tq = _dispatch_get_root_queue(
                    qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos,
    
                    overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;//串行1 并发0
            if (unlikely(!tq)) {
                DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
            }
        }
    
        // Step 2: Initialize the queue
          
            //如果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) {
            vtable = DISPATCH_VTABLE(queue_concurrent);
        } else {
            vtable = DISPATCH_VTABLE(queue_serial);
        }
        
            //设置autorelease_frequency以及如果label是muteable的转换为immutable
            ……
       // 开辟内存 - 生成响应的对象 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));
    
            // 设置label,priority,target queue
        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;
    

    区分串行和并发

    if (dqai.dqai_concurrent) {
            vtable = DISPATCH_VTABLE(queue_concurrent);
        } else {
            vtable = DISPATCH_VTABLE(queue_serial);
        }
        
    
    dispatch_queue_attr_info_t分析

    1.首先,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_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 = { };
    
            // dqa如果是null就返回空的{}
        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);
    
        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_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 = -(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;
    }
    

    看完这些,我们回到上面的_dispatch_lane_create_with_target代码去接着分析

    首先创建了一个空的结构体dqai,下面就直接判断参数dqa

    1. 如果是空,就直接返回,否则就往下走。通过代码走向,可以知道,其实这个参数,就是dispatch_queue_create()的第二个参数,串行传NULL,并发传的是非NULL

    2. 意味着如果是串行,dqai.dqai_concurrent就是为空,再回过头看一下,底层就是通过dqai.dqai_concurrent来区分并发和串行的。

    3. 串行队列传的是NULL ,所以直接返回.

    4. 并行队列,通过按位取余设置下面的各个参数

    两种队列通过dqai.dqai_concurrent区分

    _dispatch_get_root_queue分析

    _dispatch_root_queues方法定义:从数组中取出下表为6/7的地址

    _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

    根据下标去对应dispatch_queue_global_s

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

    这里其实是return _dispatch_root_queues[2 * (qos - 1) + overcommit]
    也就是说target queue就是从_dispatch_root_queues队列里面拿第(2 * (qos - 1) + overcommit)个queue,由于QOS最大为6,并且还有over commit的区分.
    注意串行queue默认是overcommit的为1,并行是不overcommit的为0

    typedef enum {
    _dispatch_queue_attr_overcommit_unspecified = 0,
    _dispatch_queue_attr_overcommit_enabled,
    _dispatch_queue_attr_overcommit_disabled,
    } _dispatch_queue_attr_overcommit_t;

    • qos的枚举值
    
    #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)
    
    创建target queue

    _dispatch_lane_create_with_target有如下代码

    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);
    }
    
        //设置autorelease_frequency以及如果label是muteable的转换为immutable
        ……
    
    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));
    
    1. 首先通过了dqai.dqai_concurrent来设置了vtable
      通过各种宏可以知道其实并行queuevtable就是OS_dispatch_concurrent_class
      串行queue的的vtable就是OS_dispatch_serial_class,这也就是两种queue对应的class
    #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
    
    1. 通过_dispatch_object_allocvtable类分配了内存空间,大小为dispatch_lane_s结构体的大小
    dispatch_lane_t dq = _dispatch_object_alloc(vtable,
                sizeof(struct dispatch_lane_s));
                
    typedef struct dispatch_lane_s *dispatch_queue_serial_t;
    typedef struct dispatch_lane_s *dispatch_queue_concurrent_t;
    
    1. 通过_dispatch_queue_init初始化queue

    这一段主要是设置statewidth之类的

    static inline dispatch_queue_class_t
    _dispatch_queue_init(dispatch_queue_class_t dqu, dispatch_queue_flags_t dqf,
            uint16_t width, uint64_t initial_state_bits)
    {
        uint64_t dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(width);
        dispatch_queue_t dq = dqu._dq;
    
        dispatch_assert((initial_state_bits & ~(DISPATCH_QUEUE_ROLE_MASK |
                DISPATCH_QUEUE_INACTIVE)) == 0);
    
        if (initial_state_bits & DISPATCH_QUEUE_INACTIVE) {
            dq->do_ref_cnt += 2; // rdar://8181908 see _dispatch_lane_resume
            if (dx_metatype(dq) == _DISPATCH_SOURCE_TYPE) {
                dq->do_ref_cnt++; // released when DSF_DELETED is set
            }
        }
    
        dq_state |= initial_state_bits;
        dq->do_next = DISPATCH_OBJECT_LISTLESS;
        dqf |= DQF_WIDTH(width);
        os_atomic_store2o(dq, dq_atomic_flags, dqf, relaxed);
        dq->dq_state = dq_state;
        dq->dq_serialnum =
                os_atomic_inc_orig(&_dispatch_queue_serial_numbers, relaxed);
        return dqu;
    }
    
    1. width:最大并发的线程数
    #define DISPATCH_QUEUE_WIDTH_MAX  (DISPATCH_QUEUE_WIDTH_FULL - 2)  //4094
    #define DISPATCH_QUEUE_WIDTH_FULL           0x1000ull
    
    1. initial_state:这个queue是不是一开始就是active状态,如果不是的话,需要手动执行dispatch_active以后才能激活
    // inactive的initial_state_bits如下,如果是一开始就active的initial_state_bits为0
    #define DISPATCH_QUEUE_INACTIVE             0x0100000000000000ull
    
    1. 设置priority、label、target queue
    2. 返回_dispatch_trace_queue_create(queue)将队列插入到队列数组中,设置队列头尾节点等

    总结
    target:com.apple.root.default-qos com.apple.root.default-qos.overcommit
    width: DISPATCH_QUEUE_WIDTH_FULL - 2(0xffe) 0x1000ull(0x1)

    都得以验证.

    我们创建串行queue的时候是取的第2 * (qos - 1) + overcommit = 2 * (DISPATCH_QOS_DEFAULT - 1) + 1 = 2 * (4 - 1) + 1 = 7个queue,也就是"com.apple.root.default-qos.overcommit",和上面试验创建串行queue拿到的target queue是一致的。下标0开始;

    • 创建一个新queue的任务比较重要的几步主要是:
      · 设置一下各种参数给dqai
      · 用_dispatch_get_root_queue创建一个target queue
      · 用_dispatch_object_alloc分配内存,并通过_dispatch_queue_init创建一个queue
      · 将各种label、qos等设置给queue
      · 调用_dispatch_trace_queue_create返回一个queue

    dispatch_get_main_queue

    dispatch_queue_main_t
    dispatch_get_main_queue(void)
    {
        return 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_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_default_queue 是一个宏定义
    #define _dispatch_get_default_queue(overcommit) \
            _dispatch_root_queues[DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS + \
                    !!(overcommit)]._as_dq
    
    • overcommit qos index values need bit 1 set
    
    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_QOS=6, overcommit为true,所以main_queue拿的是_dispatch_root_queues里面的第个,也就是"com.apple.root.default-qos.overcommit",和串行queue拿到的target queue是一致的

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

    获取global对列的最后也是转调的_dispatch_get_root_queue,返回_dispatch_root_queues[2 * (qos - 1) + overcommit],在这个场景下的QOSDISPATCH_QOS_DEFAULT=4(对应priority0的时候),默认overcommit也是0,所以拿的是第6queue,也就是"com.apple.root.default-qos"

    总结一下各种queue的获取方式吧

    1. 自己create创建的queue是需要alloc分配内存以后init,最后从root_queue里面的拿一个作为新queuetarget queue
    2. mainglobal queue是不需要alloc init的,直接从root_queue里拿出对应的queue即可.

    相关文章

      网友评论

          本文标题:iOS---17----多线程之GCD

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