11--多線程探索06--GCD源碼之dispatch_queue_create

上一回從public API的角度看了如何新建一個(gè)隊(duì)列、哪些字段有關(guān)隊(duì)列優(yōu)先級(jí)吻育、以及隊(duì)列的優(yōu)先級(jí)怎么設(shè)置念秧。這一回就從源碼的角度來證實(shí)上一回的猜測(cè)。

一布疼、_dispatch_lane_create_with_target 探索

1.1 dispatch_get_main_queue()

  1. 轉(zhuǎn)寫成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的類型定義的文章中解釋的非常詳細(xì)了游两;
  • 第二行:.do_targetq = _dispatch_get_default_queue(true)砾层,在上一回的講解中已經(jīng)知道了,主隊(duì)列仍然依賴于一個(gè)根隊(duì)列贱案,而這里便是對(duì)targetq的設(shè)置肛炮,最后會(huì)走到_dispatch_root_queues方法中去,這個(gè)方法放在下面做講解;
  • 第三行:.dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(1) | DISPATCH_QUEUE_ROLE_BASE_ANON铸董,上一回的日志中就看到了這個(gè)屬性祟印,從這里的賦值來看,這個(gè)屬性是一個(gè)比較大的數(shù)值粟害,具體值的大小可以在源碼中看到蕴忆,主隊(duì)列的默認(rèn)值為:0x001ffe1000000000,而最終輸出的值不一樣悲幅,說明后面修改過該值套鹅。
    dq_state初始值
  • 第四行:.dq_label = "com.apple.main-thread",主隊(duì)列的標(biāo)識(shí)汰具,跟輸出的結(jié)果一致卓鹿;
  • 第五行:.dq_atomic_flags = DQF_THREAD_BOUND | DQF_WIDTH(1),可能跟線程安全相關(guān)留荔;
  • 第六行:.dq_serialnum = 1吟孙,很簡(jiǎn)單的猜測(cè)為串行隊(duì)列,任務(wù)數(shù)為1聚蝶;

1.2 dispatch_get_global_queue()

在源碼中找到dispatch_get_global_queue的定義杰妓。代碼邏輯非常簡(jiǎn)單,確定隊(duì)列的優(yōu)先級(jí)碘勉,然后根據(jù)優(yōu)先級(jí)獲取一個(gè)根隊(duì)列巷挥。
第一行:flags & ~(unsigned long)DISPATCH_QUEUE_OVERCOMMIT,做了一個(gè)限制验靡,保證任何非0數(shù)都返回一個(gè)NULL倍宾。(實(shí)測(cè)2是可以通過的,可能是將來預(yù)留的某種標(biāo)識(shí)胜嗓,實(shí)際中別使用高职,玩源碼的時(shí)候可以測(cè)試下)。
最后根據(jù)_dispatch_get_root_queue辞州,返回一個(gè)根隊(duì)列初厚,函數(shù)的第二個(gè)參數(shù)很有意思,flag=0孙技,那么這個(gè)參數(shù)就定為false,也即并行隊(duì)列排作。

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方法牵啦。
前面兩個(gè)參數(shù):labelattr上一回講過了妄痪,并會(huì)透?jìng)鞯较聦臃椒ǎ?br> 后面兩個(gè)參數(shù):tq:DISPATCH_TARGET_QUEUE_DEFAULT表示新建一個(gè)隊(duì)列的默認(rèn)targetq是默認(rèn)優(yōu)先級(jí)的哈雏,legacy:true表示使用遺留類。具體的含義會(huì)在_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 流程

對(duì)源碼取出一些條件判斷土浸,取出主流程,這里忽略的legacy參數(shù)相關(guān)邏輯彭羹,這個(gè)參數(shù)主要是控制隊(duì)列的釋放條件黄伊。剩余部分如下所示:

static dispatch_queue_t
_dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
        dispatch_queue_t tq, bool legacy)
{
    // 獲取隊(duì)列屬性描述
    dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);

    // 步驟 1:通用參數(shù)設(shè)置

    // 關(guān)于 qos 的一些判斷條件省略,直接取重點(diǎn)流程
    dispatch_qos_t qos = dqai.dqai_qos;
    _dispatch_queue_attr_overcommit_t overcommit = dqai.dqai_overcommit;
    
    // 串行隊(duì)列默認(rèn)是 overcommit
    overcommit = dqai.dqai_concurrent ?
            _dispatch_queue_attr_overcommit_disabled :
            _dispatch_queue_attr_overcommit_enabled;
    // 設(shè)置 targetq
    tq = _dispatch_get_root_queue(
                qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT/*4*/ : qos,
                overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;

    // 步驟 2:初始化隊(duì)列

    const void *vtable;
    // 設(shè)置隊(duì)列標(biāo)識(shí)
    dispatch_queue_flags_t dqf = legacy ? DQF_MUTABLE : 0;
    // 設(shè)置是串行隊(duì)列還是并行隊(duì)列
    if (dqai.dqai_concurrent) {
        vtable = DISPATCH_VTABLE(queue_concurrent);
    } else {
        vtable = DISPATCH_VTABLE(queue_serial);
    }
    // 配置隊(duì)列的標(biāo)簽
    if (label) {
        const char *tmp = _dispatch_strdup_if_mutable(label);
        label = tmp;
    }
    // 分配隊(duì)列內(nèi)存
    dispatch_lane_t dq = _dispatch_object_alloc(vtable,
            sizeof(struct dispatch_lane_s));
    // 初始化隊(duì)列
    _dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
            DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
            (dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
    // 設(shè)置隊(duì)列標(biāo)簽
    dq->dq_label = label;
    // 設(shè)置隊(duì)列優(yōu)先級(jí)
    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;
    }
    // 設(shè)置并持有目標(biāo)隊(duì)列
    _dispatch_retain(tq);
    dq->do_targetq = tq;
    // 返回隊(duì)列
    return _dispatch_trace_queue_create(dq)._dq;
}

2.1 _dispatch_queue_attr_to_info(dqa)

dqa就是通過dispatch_queue_create的第二個(gè)參數(shù)透?jìng)鬟^來的值派殷。這個(gè)屬性包含的值也是相當(dāng)有限的还最,但在創(chuàng)建隊(duì)列的過程中,非常依賴由dqa這個(gè)值生成的結(jié)果dqai毡惜,說明GCD中的屬性之間會(huì)有比較多的關(guān)聯(lián)拓轻。例如:dqai_concurrent可以確定overcommit屬性,而overcommit的值又會(huì)影響dq_priority屬性经伙。而蘋果將它們都通過計(jì)算存在一個(gè)值里面扶叉。可以看一下它的賦值過程:

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;

有興趣的話帕膜,可以每個(gè)值都替換進(jìn)去枣氧,看一看類型的變化。

2.2 通用參數(shù)設(shè)置

這一步主要設(shè)置以下三個(gè)屬性:

qos = dqai.dqai_qos

  1. 外部傳進(jìn)來的 attr泳叠;
  2. 將 attr 中的優(yōu)先級(jí)保存進(jìn) info 中 qos 字段作瞄;
  3. 取 info 中的 qos;

overcommit = dqai.dqai_concurrent ? _dispatch_queue_attr_overcommit_disabled : _dispatch_queue_attr_overcommit_enabled

  1. 外部傳進(jìn)來的 attr危纫;
  2. 將 attr 中串行/并行屬性保存進(jìn) info 中 dqai_concurrent 字段宗挥;
  3. 根據(jù) info 中 dqai_concurrent 決定 overcommit 字段。并行隊(duì)列:disabled种蝶,串行隊(duì)列:enabled

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

  1. 根據(jù)上面得到的 qosovercommit 來獲取 target契耿;
  2. 走到 _dispatch_get_root_queue 流程;

2.3 初始化隊(duì)列

  1. 分配內(nèi)存螃征。這個(gè)方法最終會(huì)調(diào)到:malloc_zone_calloc(_dispatch_ccache_zone, (n), (s))
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
            sizeof(struct dispatch_lane_s));
  1. 初始化隊(duì)列搪桂。內(nèi)部會(huì)根據(jù)幾個(gè)參數(shù)對(duì)隊(duì)列的屬性進(jìn)行初始化。
_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引用計(jì)數(shù)+1踢械,targetq指針指向tq。
// 設(shè)置并持有目標(biāo)隊(duì)列
_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的優(yōu)先級(jí)
  • dqai_relpri:關(guān)聯(lián)優(yōu)先級(jí)内列。queue在target中的優(yōu)先級(jí)
  • dqai_overcommit:是否可以overcommit。依賴于dqai_concurrent屬性背率,串行隊(duì)列:overcommit為true话瞧,并行隊(duì)列為false
  • dqai_autorelease_frequency:自動(dòng)釋放頻率
  • dqai_concurrent:是否是并行隊(duì)列
  • dqai_inactive:是否激活

下面可以靜態(tài)感受一下蘋果對(duì) info 的賦值:

  1. 取出一個(gè)相對(duì)下標(biāo)嫩与;
  2. 然后對(duì)每個(gè)段輾轉(zhuǎn)取余;
  3. 取完某個(gè)段的值之后便將其移除交排;
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內(nèi)部調(diào)用的方法是這樣划滋,上一回講到的dispatch_queue_attr_make_with_qos_class方法中也是用的類似的方法給屬性賦值,包括另外兩個(gè)未展開講解的方法也是一樣:

  • dispatch_queue_attr_make_initially_inactive
  • dispatch_queue_attr_make_with_autorelease_frequency

下面附上這三個(gè)方法的源碼:

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

到這里埃篓,隊(duì)列中的屬性就是非常明了了处坪。

【補(bǔ)充】dispatch_autorelease_frequency關(guān)于create流程中l(wèi)egacy參數(shù)確定的取值

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
    繼承目標(biāo)隊(duì)列的釋放頻率
    與目標(biāo)隊(duì)列的釋放頻率保持一致
  • DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM
    在每個(gè)block被異步添加到隊(duì)列中的時(shí)候push
    在每個(gè)block執(zhí)行完成之后pop
  • DISPATCH_AUTORELEASE_FREQUENCY_NEVER
    這種類型只針對(duì)全局隊(duì)列
    并且不支持自定義的自動(dòng)釋放池的push和pop

四、_dispatch_root_queues 詳解

_dispatch_root_queues源碼如下:

  1. _DISPATCH_ROOT_QUEUE_IDX宏定義是獲取根隊(duì)列的最終類型都许;
  2. _DISPATCH_ROOT_QUEUE_ENTRY宏定義是給這個(gè)根隊(duì)列中的屬性進(jìn)行賦值稻薇;
  3. 從第三個(gè)代碼塊到最后一個(gè)代碼塊,一起12個(gè)代碼塊胶征。
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條系統(tǒng)維護(hù)的根隊(duì)列
  • 每一種優(yōu)先級(jí)的隊(duì)列都有串行和并行兩種
  • 也就是有6種塞椎,這六種優(yōu)先從上到下遞減
     __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
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市睛低,隨后出現(xiàn)的幾起案子案狠,更是在濱河造成了極大的恐慌,老刑警劉巖钱雷,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骂铁,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡罩抗,警方通過查閱死者的電腦和手機(jī)拉庵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來套蒂,“玉大人钞支,你說我怎么就攤上這事〔俚叮” “怎么了烁挟?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)骨坑。 經(jīng)常有香客問我撼嗓,道長(zhǎng),這世上最難降的妖魔是什么欢唾? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任且警,我火速辦了婚禮,結(jié)果婚禮上礁遣,老公的妹妹穿的比我還像新娘振湾。我一直安慰自己,他們只是感情好亡脸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布押搪。 她就那樣靜靜地躺著,像睡著了一般浅碾。 火紅的嫁衣襯著肌膚如雪大州。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天垂谢,我揣著相機(jī)與錄音厦画,去河邊找鬼。 笑死滥朱,一個(gè)胖子當(dāng)著我的面吹牛根暑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播徙邻,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼排嫌,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了缰犁?” 一聲冷哼從身側(cè)響起淳地,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎帅容,沒想到半個(gè)月后颇象,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡并徘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年遣钳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片麦乞。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蕴茴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出路幸,到底是詐尸還是另有隱情荐开,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布简肴,位于F島的核電站晃听,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏砰识。R本人自食惡果不足惜能扒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辫狼。 院中可真熱鬧初斑,春花似錦、人聲如沸膨处。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鹃答,卻和暖如春乎澄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背测摔。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工置济, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人锋八。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓浙于,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親挟纱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子羞酗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 想了許久,還是決定將GCD的內(nèi)容盡量寫得簡(jiǎn)單一點(diǎn)樊销,所以多分幾個(gè)章節(jié)整慎,每個(gè)章節(jié)內(nèi)容盡量少。 一围苫、如何創(chuàng)建一個(gè)隊(duì)列 G...
    修_遠(yuǎn)閱讀 2,325評(píng)論 0 4
  • 隊(duì)列 GCD隊(duì)列的創(chuàng)建裤园,不外乎兩種情況,串行和并發(fā) 上面完整的輸出了串行和并發(fā)隊(duì)列的信息剂府,下面就通過底層代碼看看是...
    佐_籩閱讀 605評(píng)論 0 2
  • iOS Objective-C GCD之queue(隊(duì)列)篇 GCD全稱Grand Central Dispatc...
    just東東閱讀 3,245評(píng)論 0 4
  • 閱讀源碼是枯燥的拧揽,可能暫時(shí)對(duì)我們的工作沒什么幫助,現(xiàn)在但是作為一個(gè)有一定開發(fā)經(jīng)驗(yàn)的開發(fā)人員而言腺占,這一步是必須要走的...
    我叫Vincent閱讀 1,877評(píng)論 0 2
  • GCD源碼官網(wǎng)下載地址 GCD的源碼在我看來淤袜,一直是iOS源碼中最晦澀難懂一種,因?yàn)樯婕暗教嗟暮甓x和結(jié)構(gòu)定義衰伯,...
    默默_David閱讀 491評(píng)論 0 2