11--多线程探索06--GCD源码之dispatch_queue_create

上一回从public API的角度看了如何新建一个队列、哪些字段有关队列优先级、以及队列的优先级怎么设置。这一回就从源码的角度来证实上一回的猜测。

一、_dispatch_lane_create_with_target 探索

1.1 dispatch_get_main_queue()

  1. 转写成cpp文件:xcrun -sdk iphonesimulator clang -arch x86_64 -rewrite-objc main.m,得到以下信息:_dispatch_main_q
dispatch_queue_main_t
dispatch_get_main_queue(void)
{
 return (( dispatch_queue_main_t)&(_dispatch_main_q));
}
  1. 在GCD源码中找到_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_GLOBAL_OBJECT_HEADER(queue_main),在GCD的类型定义的文章中解释的非常详细了;
  • 第二行:.do_targetq = _dispatch_get_default_queue(true),在上一回的讲解中已经知道了,主队列仍然依赖于一个根队列,而这里便是对targetq的设置,最后会走到_dispatch_root_queues方法中去,这个方法放在下面做讲解;
  • 第三行:.dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(1) | DISPATCH_QUEUE_ROLE_BASE_ANON,上一回的日志中就看到了这个属性,从这里的赋值来看,这个属性是一个比较大的数值,具体值的大小可以在源码中看到,主队列的默认值为:0x001ffe1000000000,而最终输出的值不一样,说明后面修改过该值。
    dq_state初始值
  • 第四行:.dq_label = "com.apple.main-thread",主队列的标识,跟输出的结果一致;
  • 第五行:.dq_atomic_flags = DQF_THREAD_BOUND | DQF_WIDTH(1),可能跟线程安全相关;
  • 第六行:.dq_serialnum = 1,很简单的猜测为串行队列,任务数为1;

1.2 dispatch_get_global_queue()

在源码中找到dispatch_get_global_queue的定义。代码逻辑非常简单,确定队列的优先级,然后根据优先级获取一个根队列。
第一行:flags & ~(unsigned long)DISPATCH_QUEUE_OVERCOMMIT,做了一个限制,保证任何非0数都返回一个NULL。(实测2是可以通过的,可能是将来预留的某种标识,实际中别使用,玩源码的时候可以测试下)。
最后根据_dispatch_get_root_queue,返回一个根队列,函数的第二个参数很有意思,flag=0,那么这个参数就定为false,也即并行队列。

dispatch_queue_global_t
dispatch_get_global_queue(intptr_t priority, uintptr_t 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);
}

1.3 dispatch_queue_create()

dispatch_queue_create方法最终走到了_dispatch_lane_create_with_target方法。
前面两个参数:labelattr上一回讲过了,并会透传到下层方法;
后面两个参数:tq:DISPATCH_TARGET_QUEUE_DEFAULT表示新建一个队列的默认targetq是默认优先级的,legacy:true表示使用遗留类。具体的含义会在_dispatch_lane_create_with_target 流程中讲解。

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 流程

对源码取出一些条件判断,取出主流程,这里忽略的legacy参数相关逻辑,这个参数主要是控制队列的释放条件。剩余部分如下所示:

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

    // 步骤 1:通用参数设置

    // 关于 qos 的一些判断条件省略,直接取重点流程
    dispatch_qos_t qos = dqai.dqai_qos;
    _dispatch_queue_attr_overcommit_t overcommit = dqai.dqai_overcommit;
    
    // 串行队列默认是 overcommit
    overcommit = dqai.dqai_concurrent ?
            _dispatch_queue_attr_overcommit_disabled :
            _dispatch_queue_attr_overcommit_enabled;
    // 设置 targetq
    tq = _dispatch_get_root_queue(
                qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT/*4*/ : qos,
                overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;

    // 步骤 2:初始化队列

    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);
    }
    // 配置队列的标签
    if (label) {
        const char *tmp = _dispatch_strdup_if_mutable(label);
        label = tmp;
    }
    // 分配队列内存
    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;
    }
    // 设置并持有目标队列
    _dispatch_retain(tq);
    dq->do_targetq = tq;
    // 返回队列
    return _dispatch_trace_queue_create(dq)._dq;
}

2.1 _dispatch_queue_attr_to_info(dqa)

dqa就是通过dispatch_queue_create的第二个参数透传过来的值。这个属性包含的值也是相当有限的,但在创建队列的过程中,非常依赖由dqa这个值生成的结果dqai,说明GCD中的属性之间会有比较多的关联。例如:dqai_concurrent可以确定overcommit属性,而overcommit的值又会影响dq_priority属性。而苹果将它们都通过计算存在一个值里面。可以看一下它的赋值过程:

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

有兴趣的话,可以每个值都替换进去,看一看类型的变化。

2.2 通用参数设置

这一步主要设置以下三个属性:

qos = dqai.dqai_qos

  1. 外部传进来的 attr;
  2. 将 attr 中的优先级保存进 info 中 qos 字段;
  3. 取 info 中的 qos;

overcommit = dqai.dqai_concurrent ? _dispatch_queue_attr_overcommit_disabled : _dispatch_queue_attr_overcommit_enabled

  1. 外部传进来的 attr;
  2. 将 attr 中串行/并行属性保存进 info 中 dqai_concurrent 字段;
  3. 根据 info 中 dqai_concurrent 决定 overcommit 字段。并行队列:disabled,串行队列:enabled

tq = _dispatch_get_root_queue( qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT/*4*/ : qos, overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;

  1. 根据上面得到的 qosovercommit 来获取 target;
  2. 走到 _dispatch_get_root_queue 流程;

2.3 初始化队列

  1. 分配内存。这个方法最终会调到:malloc_zone_calloc(_dispatch_ccache_zone, (n), (s))
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
            sizeof(struct dispatch_lane_s));
  1. 初始化队列。内部会根据几个参数对队列的属性进行初始化。
_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. 持有tq。targetq引用计数+1,targetq指针指向tq。
// 设置并持有目标队列
_dispatch_retain(tq);
dq->do_targetq = tq;

三、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;
  • dqai_qos:queue的target的优先级
  • dqai_relpri:关联优先级。queue在target中的优先级
  • dqai_overcommit:是否可以overcommit。依赖于dqai_concurrent属性,串行队列:overcommit为true,并行队列为false
  • dqai_autorelease_frequency:自动释放频率
  • dqai_concurrent:是否是并行队列
  • dqai_inactive:是否激活

下面可以静态感受一下苹果对 info 的赋值:

  1. 取出一个相对下标;
  2. 然后对每个段辗转取余;
  3. 取完某个段的值之后便将其移除;
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_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;

上面的宏定义:

#define DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT 3

#define DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT 3

#define DISPATCH_QUEUE_ATTR_QOS_COUNT (DISPATCH_QOS_MAX + 1)

#define DISPATCH_QUEUE_ATTR_PRIO_COUNT (1 - QOS_MIN_RELATIVE_PRIORITY)

#define DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT 2

#define DISPATCH_QUEUE_ATTR_INACTIVE_COUNT 2

#define DISPATCH_QUEUE_ATTR_COUNT  ( \
    DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT * \
    DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT * \
    DISPATCH_QUEUE_ATTR_QOS_COUNT * \
    DISPATCH_QUEUE_ATTR_PRIO_COUNT * \
    DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT * \
    DISPATCH_QUEUE_ATTR_INACTIVE_COUNT )
#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)
typedef unsigned long pthread_priority_t;
#define QOS_MIN_RELATIVE_PRIORITY (-15)
#define _PTHREAD_PRIORITY_FLAGS_MASK (~0xffffff)
#define _PTHREAD_PRIORITY_QOS_CLASS_MASK 0x00ffff00
#define _PTHREAD_PRIORITY_QOS_CLASS_SHIFT (8ull)
#define _PTHREAD_PRIORITY_PRIORITY_MASK 0x000000ff
#define _PTHREAD_PRIORITY_OVERCOMMIT_FLAG 0x80000000
#define _PTHREAD_PRIORITY_SCHED_PRI_FLAG 0x20000000
#define _PTHREAD_PRIORITY_FALLBACK_FLAG 0x04000000
#define _PTHREAD_PRIORITY_EVENT_MANAGER_FLAG 0x02000000
#define _PTHREAD_PRIORITY_NEEDS_UNBIND_FLAG 0x01000000
#define _PTHREAD_PRIORITY_ENFORCE_FLAG  0x10000000

除了GCD内部调用的方法是这样,上一回讲到的dispatch_queue_attr_make_with_qos_class方法中也是用的类似的方法给属性赋值,包括另外两个未展开讲解的方法也是一样:

  • dispatch_queue_attr_make_initially_inactive
  • dispatch_queue_attr_make_with_autorelease_frequency

下面附上这三个方法的源码:

dispatch_queue_attr_t
dispatch_queue_attr_make_with_qos_class(dispatch_queue_attr_t dqa,
        dispatch_qos_class_t qos_class, int relpri)
{
    if (!_dispatch_qos_class_valid(qos_class, relpri)) {
        return (dispatch_queue_attr_t)dqa;
    }
    dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
    dqai.dqai_qos = _dispatch_qos_from_qos_class(qos_class);
    dqai.dqai_relpri = relpri;
    return _dispatch_queue_attr_from_info(dqai);
}

dispatch_queue_attr_t
dispatch_queue_attr_make_initially_inactive(dispatch_queue_attr_t dqa)
{
    dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
    dqai.dqai_inactive = true;
    return _dispatch_queue_attr_from_info(dqai);
}

dispatch_queue_attr_t
dispatch_queue_attr_make_with_autorelease_frequency(dispatch_queue_attr_t dqa,
        dispatch_autorelease_frequency_t frequency)
{
    switch (frequency) {
    case DISPATCH_AUTORELEASE_FREQUENCY_INHERIT:
    case DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM:
    case DISPATCH_AUTORELEASE_FREQUENCY_NEVER:
        break;
    }
    dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
    dqai.dqai_autorelease_frequency = (uint16_t)frequency;
    return _dispatch_queue_attr_from_info(dqai);
}

到这里,队列中的属性就是非常明了了。

【补充】dispatch_autorelease_frequency关于create流程中legacy参数确定的取值

DISPATCH_ENUM(dispatch_autorelease_frequency, unsigned long,
    DISPATCH_AUTORELEASE_FREQUENCY_INHERIT DISPATCH_ENUM_API_AVAILABLE(
            macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)) = 0,
    DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM DISPATCH_ENUM_API_AVAILABLE(
            macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)) = 1,
    DISPATCH_AUTORELEASE_FREQUENCY_NEVER DISPATCH_ENUM_API_AVAILABLE(
            macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)) = 2,
);
  • DISPATCH_AUTORELEASE_FREQUENCY_INHERIT
    继承目标队列的释放频率
    与目标队列的释放频率保持一致
  • DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM
    在每个block被异步添加到队列中的时候push
    在每个block执行完成之后pop
  • DISPATCH_AUTORELEASE_FREQUENCY_NEVER
    这种类型只针对全局队列
    并且不支持自定义的自动释放池的push和pop

四、_dispatch_root_queues 详解

_dispatch_root_queues源码如下:

  1. _DISPATCH_ROOT_QUEUE_IDX宏定义是获取根队列的最终类型;
  2. _DISPATCH_ROOT_QUEUE_ENTRY宏定义是给这个根队列中的属性进行赋值;
  3. 从第三个代码块到最后一个代码块,一起12个代码块。
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条系统维护的根队列
  • 每一种优先级的队列都有串行和并行两种
  • 也就是有6种,这六种优先从上到下递减
     __QOS_ENUM(qos_class, unsigned int,
         QOS_CLASS_USER_INTERACTIVE
                 __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x21,
         QOS_CLASS_USER_INITIATED
                 __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x19,
         QOS_CLASS_DEFAULT
                 __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x15,
         QOS_CLASS_UTILITY
                 __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x11,
         QOS_CLASS_BACKGROUND
                 __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x09,
         QOS_CLASS_UNSPECIFIED
                 __QOS_CLASS_AVAILABLE(macos(10.10), ios(8.0)) = 0x00,
     );
    
  • dispatch_get_main_queue
    com.apple.root.default-qos.overcommit
    QOS_CLASS_DEFAULT
    
  • dispatch_get_global_queue
    com.apple.root.default-qos
    QOS_CLASS_DEFAULT
    

你可能感兴趣的:(11--多线程探索06--GCD源码之dispatch_queue_create)