iOS-GCD原理分析(一)

前言

GCD在我們的實(shí)際開發(fā)中,用到非常之我,那么它的原理是怎么樣的,我們來分析下。

GCD概念

  • 全稱是GrandCentralDispatch
  • 純C語?,提供了?常多強(qiáng)?的函數(shù)

GCD的優(yōu)勢(shì):

  • GCD是蘋果公司為多核的并?運(yùn)算提出的解決?案

  • GCD會(huì)?動(dòng)利?更多的CPU內(nèi)核(?如雙核、四核)

  • GCD會(huì)?動(dòng)管理線程的?命周期(創(chuàng)建線程、調(diào)度任- 務(wù)、銷毀線程)

  • 程序員只需要告訴GCD想要執(zhí)?什么任務(wù),不需要編- 寫任何線程管理代碼

  • 任務(wù)使?block封裝

  • 任務(wù)的block沒有參數(shù)也沒有返回值

  • 執(zhí)?任務(wù)的函數(shù)

  • 異步dispatch_async

    • 不?等待當(dāng)前語句執(zhí)?完畢,就可以執(zhí)?下?條語句
    • 會(huì)開啟線程執(zhí)?block的任務(wù)
    • 異步是多線程的代名詞
  • 同步dispatch_sync

    • 必須等待當(dāng)前語句執(zhí)?完畢,才會(huì)執(zhí)?下?條語句
    • 不會(huì)開啟線程

函數(shù)與隊(duì)列

同步函數(shù)串行隊(duì)列

  • 不會(huì)開啟線程,在當(dāng)前線程執(zhí)行任務(wù)
  • 任務(wù)串行執(zhí)行,任務(wù)一個(gè)接一個(gè)的
  • 會(huì)產(chǎn)生堵塞

同步函數(shù)并發(fā)隊(duì)列

  • 不會(huì)開啟線程,在當(dāng)前線程執(zhí)行任務(wù)
  • 任務(wù)一個(gè)接一個(gè)的

異步函數(shù)串行隊(duì)列

  • 開啟線程一條新線程
  • 任務(wù)一個(gè)接一個(gè)

異步函數(shù)并發(fā)隊(duì)列

  • 開啟線程,在當(dāng)前線程執(zhí)行任務(wù)
  • 任務(wù)異步執(zhí)行,沒有順序,CPU調(diào)度有關(guān)

主隊(duì)列分析

基本概念

  • 專??來在主線程上調(diào)度任務(wù)的串?隊(duì)列
  • 不會(huì)開啟線程
    如果當(dāng)前主線程正在有任務(wù)執(zhí)?,那么?論主隊(duì)列中 當(dāng)前被添加了什么任務(wù),都不會(huì)被調(diào)度
  • dispatch_get_main_queue();

源碼分析

我們先來看個(gè)面試題,如下:

  // OS_dispatch_queue_serial
    dispatch_queue_t serial = dispatch_queue_create("ro", DISPATCH_QUEUE_SERIAL);
    // OS_dispatch_queue_concurrent
    // OS_dispatch_queue_concurrent
    dispatch_queue_t conque = dispatch_queue_create("robert", DISPATCH_QUEUE_CONCURRENT);
    // DISPATCH_QUEUE_SERIAL max && 1
    // queue 對(duì)象 alloc init class
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    dispatch_queue_t globQueue = dispatch_get_global_queue(0, 0);

    NSLog(@"%@-%@-%@-%@",serial,conque,mainQueue,globQueue);

當(dāng)前的隊(duì)列總共的類型有多少種?
答案是:2(串行隊(duì)列,并發(fā)隊(duì)列,主隊(duì)列(屬于串行隊(duì)列),全局隊(duì)列(屬于并發(fā)隊(duì)列))
為什么說主隊(duì)列是串行隊(duì)列?我們來看下。
我們進(jìn)去,看下dispatch_get_main_queue這個(gè)隊(duì)列的說明文檔,如圖:

1

在這里Because the main queue doesn't behave entirely like a regular serial queue,
it may have unwanted side-effects when used in processes that are not UI apps
(daemons). For such processes, the main queue should be avoided.

這里說明了主隊(duì)列就是一個(gè)串行隊(duì)列。
我們來論證一下,DISPATCH_GLOBAL_OBJECT這個(gè)宏定義是由#define DISPATCH_GLOBAL_OBJECT(type, object) ((OS_OBJECT_BRIDGE type)&(object))定義的,** OS_OBJECT_BRIDGE這里無法在往下搜了,所以我們需要在libdispatch(版本是1271.120.2)源碼**查找。

主隊(duì)列有可能是在dyld加載鏈接我們的程序之后,main函數(shù)之前創(chuàng)建。

隊(duì)列和線程是沒有關(guān)系的,隊(duì)列是可以讓線程排隊(duì),它本身是不開辟線程的。

dispatch_queue_create這個(gè)函數(shù)創(chuàng)建的時(shí)候,我們可以指定一個(gè)label,那么主隊(duì)列是不是也有這個(gè)labe呢,我們來打印下,如圖:

2

我們?cè)谶@里發(fā)下主隊(duì)列的label是com.apple.main-thread這個(gè),我們?cè)谠创a中搜下這個(gè),如圖:
3

這里找到了主隊(duì)列的創(chuàng)建。

這里.dq_atomic_flags = DQF_THREAD_BOUND | DQF_WIDTH(1),這說明了是個(gè)串行隊(duì)列。
我們接下來論證下。

串行和并發(fā)的底層源碼辨識(shí)

串行隊(duì)列必然有它自己的特性,接下來我們查看下(串行列隊(duì) VS 并發(fā)隊(duì)列)。
串行列列和并發(fā)隊(duì)列都是通過dispatch_queue_create這個(gè)創(chuàng)建的。
我們?cè)谠创a中搜下dispatch_queue_create(con(因?yàn)閘abel有可能是個(gè)const類型),得到如下:

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

我們?cè)偎阉飨? _dispatch_lane_create_with_target*這個(gè)函數(shù),代碼如下:

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,
                overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;
        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) {
        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;
        }
    }

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

我們看下它的返回值* _dispatch_trace_queue_create*是這個(gè)函數(shù)(我們只需要看它的返回值來查找串行隊(duì)列),這個(gè)函數(shù)不是我們的重點(diǎn),而這個(gè)dq才是,

dispatch_lane_t dq = _dispatch_object_alloc(vtable, sizeof(struct dispatch_lane_s));

這個(gè)是dq的創(chuàng)建代碼

_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 DISPATCH_QUEUE_WIDTH_MAX,否則轉(zhuǎn)1,我們?cè)賮砜聪? _dispatch_queue_init*這個(gè)函數(shù),如下:

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

其中

dqf |= DQF_WIDTH(width);

這行代碼就是DQF_WIDTH給了dqf,dqf等1就是串行隊(duì)列。

dq->dq_serialnum =
            os_atomic_inc_orig(&_dispatch_queue_serial_numbers, relaxed);

這行代碼dq_serialnum中,看下_dispatch_queue_serial_numbers這個(gè)參數(shù),它的定義如下:

// skip zero
// 1 - main_q
// 2 - mgr_q
// 3 - mgr_root_q
// 4,5,6,7,8,9,10,11,12,13,14,15 - global queues
// 17 - workloop_fallback_q
// we use 'xadd' on Intel, so the initial value == next assigned
#define DISPATCH_QUEUE_SERIAL_NUMBER_INIT 17
extern unsigned long volatile _dispatch_queue_serial_numbers;

這里說的很清楚 1代碼主隊(duì)列。
我們?cè)倩貋磉@個(gè)函數(shù)中_dispatch_lane_create_with_target繼續(xù)分析。

dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);

這行代碼中的* _dispatch_queue_attr_to_info*函數(shù)主要做了位移運(yùn)算,那么串行隊(duì)列在哪判斷的?

dispatch_queue_attr_info_t dqai = { };

if (!dqa) return dqai;

就是一個(gè)空的dqai,也就是串行隊(duì)列的判斷。

所以,串行隊(duì)列與并發(fā)隊(duì)列是通過DQF_WIDTH來區(qū)分的。

GCD底層源碼繼承鏈

在* _dispatch_lane_create_with_target*這個(gè)函數(shù)中的

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

這段代碼DISPATCH_VTABLE以及_dispatch_object_alloc不是dispatch_queue_t接收,而是dispatch_lane_t接收,是由_dispatch_object_alloc這個(gè)函數(shù)創(chuàng)建,而不是dispatch_queue這個(gè)函數(shù),這是為什么?
我接再進(jìn)步探索下。

下面我們來講下dispatch_get_global_queue全局并發(fā)隊(duì)列。
我們?cè)谠创a中搜過下com.apple.root.default-qos這個(gè),發(fā)現(xiàn)如下代碼:

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是一個(gè)dispatch_queue_global_s類型的數(shù)組變量。
而我們的主隊(duì)列_dispatch_main_qdispatch_queue_static_s這個(gè)struct類型的變量,而這個(gè)主隊(duì)列是通過dispatch_get_main_queuedispatch_queue_main_t這個(gè)獲取到的。
這樣看著會(huì)比較亂,我們知道主隊(duì)列,串行隊(duì)列,并發(fā)隊(duì)列都是通過dispatch_queue_t接收,我們先研究下這個(gè)。
我們發(fā)現(xiàn)dispatch_queue_t是這個(gè)

DISPATCH_DECL(dispatch_queue);

宏,最終是由

#define DISPATCH_DECL(name) OS_OBJECT_DECL_SUBCLASS(name, dispatch_object)

這個(gè)宏定義的。
這個(gè)我們?cè)谠创a中找OS_OBJECT_DECL_SUBCLASS這個(gè)宏,找到以下代碼:

#define OS_OBJECT_DECL_SUBCLASS(name, super) \
        OS_OBJECT_DECL_IMPL(name, NSObject, <OS_OBJECT_CLASS(super)>)
#define OS_OBJECT_DECL_SUBCLASS(name, super)  DISPATCH_DECL(name)

要么DISPATCH_DECL這個(gè)種類型,要么就是
OS_OBJECT_DECL_IMPL這種類型。
我們?cè)倏聪? OS_OBJECT_DECL_IMPLOS_OBJECT_CLASS*分別代表什么,經(jīng)過搜索,如下代碼:

#define OS_OBJECT_DECL_IMPL(name, adhere, ...) \
        OS_OBJECT_DECL_PROTOCOL(name, __VA_ARGS__) \
        typedef adhere<OS_OBJECT_CLASS(name)> \
                * OS_OBJC_INDEPENDENT_CLASS name##_t
#define OS_OBJECT_DECL_PROTOCOL(name, ...) \
        @protocol OS_OBJECT_CLASS(name) __VA_ARGS__ \
        @end
  • OS_OBJECT_CLASS*

又是定義的這個(gè)

#define OS_OBJECT_CLASS(name) OS_##name

也就是說傳一個(gè)dispatch_queue然后不斷往下拼接,一級(jí)一級(jí)的往下進(jìn)行封裝。

從以上分析,可以得出以下結(jié)論:

 dispatch_queue_t -> typedef struct dispatch_queue_s  ->  public dispatch_object_s {} -> _os_object_s -> dispatch_object_t*

所以: dispatch_queue_t本質(zhì)是dispatch_queue_s,dispatch_queue_s又繼承dispatch_object_s,dispatch_object_s繼于于_os_object_s,最終繼承于dispatch_object_t
最終結(jié)論 GCD的根類是dispatch_object_t。

來個(gè)面試題

 while (self.num < 5) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.num++;
        });
    }
    NSLog(@"end : %d",self.num); 

這段代碼輸出什么?答案:大于等于5。
分析:

  • 如果輸出的是0,因?yàn)槭莣hile(self.num) < 5不可能出這個(gè)循環(huán),所以0-5都會(huì)排除掉,為什么是大于等5呢。
  • 因?yàn)槭茄h(huán)里面調(diào)用了異步函數(shù),dispatch_async這個(gè)函數(shù)會(huì)開辟線程,不會(huì)阻塞線程。
    num=0,在2線程,執(zhí)行++操作
    num=0,在3線程,執(zhí)行++操作
    num=0,在4線程,執(zhí)行++操作
    num=0,在5線程,執(zhí)行++操作
    1返回的時(shí)候,在2線程,++操作
    1返回的時(shí)候,在3線程,++操作
    1返回的時(shí)候,在4線程,++操作
    這時(shí)num變?yōu)?
    在某個(gè)時(shí)刻有可能出現(xiàn)這種情況:
    當(dāng)num=5的時(shí)候,跳轉(zhuǎn)循環(huán),后臺(tái)有很多線程在執(zhí)行++操作,只是沒有回來,這個(gè)時(shí)候num>5。
    for (int i= 0; i<10000; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.num++;
        });
    }
    NSLog(@"end : %d",self.num); 

請(qǐng)問num輸出是什么?答案:小于等于10000
分析:
- 因?yàn)槭莊or循環(huán),所以這里只循環(huán)10000次。
- 因?yàn)槭钱惒骄€程,不阻塞,循環(huán)執(zhí)完畢線程,還沒 回來。

這兩個(gè)面試題說明了線程不安全

GCD的任務(wù)執(zhí)行堆棧(同步)

我們知道dispatch_sync這個(gè)函數(shù)是同步函數(shù),它的block是在什么時(shí)候執(zhí)行的,執(zhí)行流程是怎樣的,我們來分析下。
在源碼中, 我們搜索下dispatch_sync(dispa這個(gè)關(guān)鍵字,找到如下代碼:

DISPATCH_NOINLINE
void
dispatch_sync(dispatch_queue_t dq, dispatch_block_t work)
{
    uintptr_t dc_flags = DC_FLAG_BLOCK;
    if (unlikely(_dispatch_block_has_private_data(work))) {
        return _dispatch_sync_block_with_privdata(dq, work, dc_flags);
    }
    _dispatch_sync_f(dq, work, _dispatch_Block_invoke(work), dc_flags);
}
#endif // __BLOCKS__

我們要了解block的執(zhí)行流程,那就了解work這個(gè)參數(shù)是如何工作的。
_dispatch_sync_block_with_privdata和_dispatch_sync_f這兩個(gè)函數(shù)有work的參數(shù),我們來分析下。
_dispatch_sync_f中的_dispatch_Block_invoke的代碼如下:

#define _dispatch_Block_invoke(bb) \
        ((dispatch_function_t)((struct Block_layout *)bb)->invoke)

這里Block_layout就是_dispatch_Block_invoke這個(gè)。
我們需要查下_dispatch_sync_f這個(gè)在哪調(diào)用執(zhí)行的,經(jīng)過查找_dispatch_sync_f(disp這個(gè)關(guān)鍵字,如下代碼:

DISPATCH_NOINLINE
static void
_dispatch_sync_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func,
        uintptr_t dc_flags)
{
    _dispatch_sync_f_inline(dq, ctxt, func, dc_flags);
}

這里的ctxt就是work
再來看_dispatch_sync_f_inline的代碼:

DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_sync_f_inline(dispatch_queue_t dq, void *ctxt,
        dispatch_function_t func, uintptr_t dc_flags)
{
    if (likely(dq->dq_width == 1)) {
        return _dispatch_barrier_sync_f(dq, ctxt, func, dc_flags);
    }

    if (unlikely(dx_metatype(dq) != _DISPATCH_LANE_TYPE)) {
        DISPATCH_CLIENT_CRASH(0, "Queue type doesn't support dispatch_sync");
    }

    dispatch_lane_t dl = upcast(dq)._dl;
    // Global concurrent queues and queues bound to non-dispatch threads
    // always fall into the slow case, see DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE
    if (unlikely(!_dispatch_queue_try_reserve_sync_width(dl))) {
        return _dispatch_sync_f_slow(dl, ctxt, func, 0, dl, dc_flags);
    }

    if (unlikely(dq->do_targetq->do_targetq)) {
        return _dispatch_sync_recurse(dl, ctxt, func, dc_flags);
    }
    _dispatch_introspection_sync_begin(dl);
    _dispatch_sync_invoke_and_complete(dl, ctxt, func DISPATCH_TRACE_ARG(
            _dispatch_trace_item_sync_push_pop(dq, ctxt, func, dc_flags)));
}

其中

return _dispatch_barrier_sync_f(dq, ctxt, func, dc_flags);
return _dispatch_sync_f_slow(dl, ctxt, func, 0, dl, dc_flags);
return _dispatch_sync_recurse(dl, ctxt, func, dc_flags);
_dispatch_sync_invoke_and_complete(dl, ctxt, func DISPATCH_TRACE_ARG(
            _dispatch_trace_item_sync_push_pop(dq, ctxt, func, dc_flags)));

這幾個(gè)有處理有ctxt的處理,這個(gè)時(shí)候怎么辦,怎么查找,我們可以通過符號(hào)斷點(diǎn)要定位,如圖:

4

我們只需要看_dispatch_sync_f_slow這個(gè)函數(shù),代碼如下:

#pragma mark -
#pragma mark dispatch_sync / dispatch_barrier_sync

DISPATCH_NOINLINE
static void
_dispatch_sync_f_slow(dispatch_queue_class_t top_dqu, void *ctxt,
        dispatch_function_t func, uintptr_t top_dc_flags,
        dispatch_queue_class_t dqu, uintptr_t dc_flags)
{
    dispatch_queue_t top_dq = top_dqu._dq;
    dispatch_queue_t dq = dqu._dq;
    if (unlikely(!dq->do_targetq)) {
        return _dispatch_sync_function_invoke(dq, ctxt, func);
    }

    pthread_priority_t pp = _dispatch_get_priority();
    struct dispatch_sync_context_s dsc = {
        .dc_flags    = DC_FLAG_SYNC_WAITER | dc_flags,
        .dc_func     = _dispatch_async_and_wait_invoke,
        .dc_ctxt     = &dsc,
        .dc_other    = top_dq,
        .dc_priority = pp | _PTHREAD_PRIORITY_ENFORCE_FLAG,
        .dc_voucher  = _voucher_get(),
        .dsc_func    = func,
        .dsc_ctxt    = ctxt,
        .dsc_waiter  = _dispatch_tid_self(),
    };

    _dispatch_trace_item_push(top_dq, &dsc);
    __DISPATCH_WAIT_FOR_QUEUE__(&dsc, dq);

    if (dsc.dsc_func == NULL) {
        // dsc_func being cleared means that the block ran on another thread ie.
        // case (2) as listed in _dispatch_async_and_wait_f_slow.
        dispatch_queue_t stop_dq = dsc.dc_other;
        return _dispatch_sync_complete_recurse(top_dq, stop_dq, top_dc_flags);
    }

    _dispatch_introspection_sync_begin(top_dq);
    _dispatch_trace_item_pop(top_dq, &dsc);
    _dispatch_sync_invoke_and_complete_recurse(top_dq, ctxt, func,top_dc_flags
            DISPATCH_TRACE_ARG(&dsc));
}

其中

return _dispatch_sync_function_invoke(dq, ctxt, func);
    pthread_priority_t pp = _dispatch_get_priority();
    struct dispatch_sync_context_s dsc = {
        .dc_flags    = DC_FLAG_SYNC_WAITER | dc_flags,
        .dc_func     = _dispatch_async_and_wait_invoke,
        .dc_ctxt     = &dsc,
        .dc_other    = top_dq,
        .dc_priority = pp | _PTHREAD_PRIORITY_ENFORCE_FLAG,
        .dc_voucher  = _voucher_get(),
        .dsc_func    = func,
        .dsc_ctxt    = ctxt,
        .dsc_waiter  = _dispatch_tid_self(),
    };
_dispatch_sync_invoke_and_complete_recurse(top_dq, ctxt, func,top_dc_flags
            DISPATCH_TRACE_ARG(&dsc));

代碼有ctxt的處理,分析下,經(jīng)過跟蹤分析是在_dispatch_sync_function_invoke處理的,代碼如下:

static void
_dispatch_sync_function_invoke(dispatch_queue_class_t dq, void *ctxt,
        dispatch_function_t func)
{
    _dispatch_sync_function_invoke_inline(dq, ctxt, func);
}
  • _dispatch_sync_function_invoke_inline*代碼如下:
static inline void
_dispatch_sync_function_invoke_inline(dispatch_queue_class_t dq, void *ctxt,
        dispatch_function_t func)
{
    dispatch_thread_frame_s dtf;
    _dispatch_thread_frame_push(&dtf, dq);
    _dispatch_client_callout(ctxt, func);
    _dispatch_perfmon_workitem_inc();
    _dispatch_thread_frame_pop(&dtf);
}

_dispatch_client_callout(ctxt, func);這里有ctxt和func的處理,這個(gè)函數(shù)代碼如下:

void
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
    @try {
        return f(ctxt);
    }
    @catch (...) {
        objc_terminate();
    }
}

也就是dispatch_function_t傳了ctxt調(diào)用執(zhí)行。
我們bt一下,發(fā)現(xiàn)堆棧里面也是調(diào)用_dispatch_client_callout這個(gè)函數(shù),證實(shí)了我們剛才的分析。
以上結(jié)論是_dispatch_client_callout調(diào)用了block執(zhí)行。

GCD的任務(wù)執(zhí)行堆棧(異步)

我們?cè)谠创a中搜索dispatch_async(disp,得到如下代碼:

void
dispatch_async(dispatch_queue_t dq, dispatch_block_t work)
{
    dispatch_continuation_t dc = _dispatch_continuation_alloc();
    uintptr_t dc_flags = DC_FLAG_CONSUME;
    dispatch_qos_t qos;

    qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);
    _dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}

qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);代碼有處理work,我們看下_dispatch_continuation_init函數(shù)的代碼,如下:

static inline dispatch_qos_t
_dispatch_continuation_init(dispatch_continuation_t dc,
        dispatch_queue_class_t dqu, dispatch_block_t work,
        dispatch_block_flags_t flags, uintptr_t dc_flags)
{
    void *ctxt = _dispatch_Block_copy(work);

    dc_flags |= DC_FLAG_BLOCK | DC_FLAG_ALLOCATED;
    if (unlikely(_dispatch_block_has_private_data(work))) {
        dc->dc_flags = dc_flags;
        dc->dc_ctxt = ctxt;
        // will initialize all fields but requires dc_flags & dc_ctxt to be set
        return _dispatch_continuation_init_slow(dc, dqu, flags);
    }

    dispatch_function_t func = _dispatch_Block_invoke(work);
    if (dc_flags & DC_FLAG_CONSUME) {
        func = _dispatch_call_block_and_release;
    }
    return _dispatch_continuation_init_f(dc, dqu, ctxt, func, flags, dc_flags);
}

我們?cè)賮砜聪?em>_dispatch_continuation_init_f這個(gè)函數(shù)代碼,如下:

static inline dispatch_qos_t
_dispatch_continuation_init_f(dispatch_continuation_t dc,
        dispatch_queue_class_t dqu, void *ctxt, dispatch_function_t f,
        dispatch_block_flags_t flags, uintptr_t dc_flags)
{
    pthread_priority_t pp = 0;
    dc->dc_flags = dc_flags | DC_FLAG_ALLOCATED;
    dc->dc_func = f;
    dc->dc_ctxt = ctxt;
    // in this context DISPATCH_BLOCK_HAS_PRIORITY means that the priority
    // should not be propagated, only taken from the handler if it has one
    if (!(flags & DISPATCH_BLOCK_HAS_PRIORITY)) {
        pp = _dispatch_priority_propagate();
    }
    _dispatch_continuation_voucher_set(dc, flags);
    return _dispatch_continuation_priority_set(dc, dqu, pp, flags);
}

這里把f給了dc->dc_func它,ctxt給了dc->dc_ctxt = ctxt;它,進(jìn)行包裝,還把_dispatch_priority_propagate(優(yōu)先級(jí))包裝進(jìn)去,因?yàn)槭钱惒胶瘮?shù),開辟線程,必然有優(yōu)先級(jí)的處理。
_dispatch_continuation_priority_set這個(gè)函數(shù)的代碼如下:

static inline dispatch_qos_t
_dispatch_continuation_priority_set(dispatch_continuation_t dc,
        dispatch_queue_class_t dqu,
        pthread_priority_t pp, dispatch_block_flags_t flags)
{
    dispatch_qos_t qos = DISPATCH_QOS_UNSPECIFIED;
#if HAVE_PTHREAD_WORKQUEUE_QOS
    dispatch_queue_t dq = dqu._dq;

    if (likely(pp)) {
        bool enforce = (flags & DISPATCH_BLOCK_ENFORCE_QOS_CLASS);
        bool is_floor = (dq->dq_priority & DISPATCH_PRIORITY_FLAG_FLOOR);
        bool dq_has_qos = (dq->dq_priority & DISPATCH_PRIORITY_REQUESTED_MASK);
        if (enforce) {
            pp |= _PTHREAD_PRIORITY_ENFORCE_FLAG;
            qos = _dispatch_qos_from_pp_unsafe(pp);
        } else if (!is_floor && dq_has_qos) {
            pp = 0;
        } else {
            qos = _dispatch_qos_from_pp_unsafe(pp);
        }
    }
    dc->dc_priority = pp;
#else
    (void)dc; (void)dqu; (void)pp; (void)flags;
#endif
    return qos;
}

這里有qos的封裝。
所以在異步函數(shù)有做任務(wù)的封裝和優(yōu)先級(jí)的封裝,異步函數(shù)是異步調(diào)用,會(huì)產(chǎn)生無序情況,,優(yōu)先級(jí)是參考和衡量的依據(jù),回調(diào)也是異步的,CPU調(diào)度情況來決定。
CPU在某個(gè)時(shí)刻拿到我們保存的的回調(diào)的地方來調(diào)用。

所以必然要看_dispatch_continuation_async,代碼如下:

static inline void
_dispatch_continuation_async(dispatch_queue_class_t dqu,
        dispatch_continuation_t dc, dispatch_qos_t qos, uintptr_t dc_flags)
{
#if DISPATCH_INTROSPECTION
    if (!(dc_flags & DC_FLAG_NO_INTROSPECTION)) {
        _dispatch_trace_item_push(dqu, dc);
    }
#else
    (void)dc_flags;
#endif
    return dx_push(dqu._dq, dc, qos);
}

其中dx_push宏定義

#define dx_push(x, y, z) dx_vtable(x)->dq_push(x, y, z)

我們因?yàn)?em>dx_vtable調(diào)用的是dq_push,所以我們看dq_push,經(jīng)過搜索. dq_push,得到如下圖:

5

我們?cè)倏聪?em>_dispatch_root_queue_push是全局并發(fā)的賦值,搜索下,得到如下代碼:

void
_dispatch_root_queue_push(dispatch_queue_global_t rq, dispatch_object_t dou,
        dispatch_qos_t qos)
{
#if DISPATCH_USE_KEVENT_WORKQUEUE
    dispatch_deferred_items_t ddi = _dispatch_deferred_items_get();
    if (unlikely(ddi && ddi->ddi_can_stash)) {
        dispatch_object_t old_dou = ddi->ddi_stashed_dou;
        dispatch_priority_t rq_overcommit;
        rq_overcommit = rq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT;

        if (likely(!old_dou._do || rq_overcommit)) {
            dispatch_queue_global_t old_rq = ddi->ddi_stashed_rq;
            dispatch_qos_t old_qos = ddi->ddi_stashed_qos;
            ddi->ddi_stashed_rq = rq;
            ddi->ddi_stashed_dou = dou;
            ddi->ddi_stashed_qos = qos;
            _dispatch_debug("deferring item %p, rq %p, qos %d",
                    dou._do, rq, qos);
            if (rq_overcommit) {
                ddi->ddi_can_stash = false;
            }
            if (likely(!old_dou._do)) {
                return;
            }
            // push the previously stashed item
            qos = old_qos;
            rq = old_rq;
            dou = old_dou;
        }
    }
#endif
#if HAVE_PTHREAD_WORKQUEUE_QOS
    if (_dispatch_root_queue_push_needs_override(rq, qos)) {
        return _dispatch_root_queue_push_override(rq, dou, qos);
    }
#else
    (void)qos;
#endif
    _dispatch_root_queue_push_inline(rq, dou, dou, 1);
}

這里return _dispatch_root_queue_push_override(rq, dou, qos);_dispatch_root_queue_push_inline(rq, dou, dou, 1);這里有qos。
我們看下_dispatch_root_queue_push_inline這個(gè)函數(shù),代碼如下:

static inline void
_dispatch_root_queue_push_inline(dispatch_queue_global_t dq,
        dispatch_object_t _head, dispatch_object_t _tail, int n)
{
    struct dispatch_object_s *hd = _head._do, *tl = _tail._do;
    if (unlikely(os_mpsc_push_list(os_mpsc(dq, dq_items), hd, tl, do_next))) {
        return _dispatch_root_queue_poke(dq, n, 0);
    }
}

我們?cè)偎阉飨?em>_dispatch_root_queue_poke這個(gè)函數(shù),
代碼如下:

void
_dispatch_root_queue_poke(dispatch_queue_global_t dq, int n, int floor)
{
    if (!_dispatch_queue_class_probe(dq)) {
        return;
    }
#if !DISPATCH_USE_INTERNAL_WORKQUEUE
#if DISPATCH_USE_PTHREAD_POOL
    if (likely(dx_type(dq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE))
#endif
    {
        if (unlikely(!os_atomic_cmpxchg2o(dq, dgq_pending, 0, n, relaxed))) {
            _dispatch_root_queue_debug("worker thread request still pending "
                    "for global queue: %p", dq);
            return;
        }
    }
#endif // !DISPATCH_USE_INTERNAL_WORKQUEUE
    return _dispatch_root_queue_poke_slow(dq, n, floor);
}

這里有一個(gè)_dispatch_root_queue_poke_slow(dq, n, floor)這里有這個(gè)函數(shù),它的代碼如下:

static void
_dispatch_root_queue_poke_slow(dispatch_queue_global_t dq, int n, int floor)
{
    int remaining = n;
#if !defined(_WIN32)
    int r = ENOSYS;
#endif

    _dispatch_root_queues_init();
    _dispatch_debug_root_queue(dq, __func__);
    _dispatch_trace_runtime_event(worker_request, dq, (uint64_t)n);

#if !DISPATCH_USE_INTERNAL_WORKQUEUE
#if DISPATCH_USE_PTHREAD_ROOT_QUEUES
    if (dx_type(dq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE)
#endif
    {
        _dispatch_root_queue_debug("requesting new worker thread for global "
                "queue: %p", dq);
        r = _pthread_workqueue_addthreads(remaining,
                _dispatch_priority_to_pp_prefer_fallback(dq->dq_priority));
        (void)dispatch_assume_zero(r);
        return;
    }
#endif // !DISPATCH_USE_INTERNAL_WORKQUEUE
#if DISPATCH_USE_PTHREAD_POOL
    dispatch_pthread_root_queue_context_t pqc = dq->do_ctxt;
    if (likely(pqc->dpq_thread_mediator.do_vtable)) {
        while (dispatch_semaphore_signal(&pqc->dpq_thread_mediator)) {
            _dispatch_root_queue_debug("signaled sleeping worker for "
                    "global queue: %p", dq);
            if (!--remaining) {
                return;
            }
        }
    }

    bool overcommit = dq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT;
    if (overcommit) {
        os_atomic_add2o(dq, dgq_pending, remaining, relaxed);
    } else {
        if (!os_atomic_cmpxchg2o(dq, dgq_pending, 0, remaining, relaxed)) {
            _dispatch_root_queue_debug("worker thread request still pending for "
                    "global queue: %p", dq);
            return;
        }
    }

    int can_request, t_count;
    // seq_cst with atomic store to tail <rdar://problem/16932833>
    t_count = os_atomic_load2o(dq, dgq_thread_pool_size, ordered);
    do {
        can_request = t_count < floor ? 0 : t_count - floor;
        if (remaining > can_request) {
            _dispatch_root_queue_debug("pthread pool reducing request from %d to %d",
                    remaining, can_request);
            os_atomic_sub2o(dq, dgq_pending, remaining - can_request, relaxed);
            remaining = can_request;
        }
        if (remaining == 0) {
            _dispatch_root_queue_debug("pthread pool is full for root queue: "
                    "%p", dq);
            return;
        }
    } while (!os_atomic_cmpxchgv2o(dq, dgq_thread_pool_size, t_count,
            t_count - remaining, &t_count, acquire));

#if !defined(_WIN32)
    pthread_attr_t *attr = &pqc->dpq_thread_attr;
    pthread_t tid, *pthr = &tid;
#if DISPATCH_USE_MGR_THREAD && DISPATCH_USE_PTHREAD_ROOT_QUEUES
    if (unlikely(dq == &_dispatch_mgr_root_queue)) {
        pthr = _dispatch_mgr_root_queue_init();
    }
#endif
    do {
        _dispatch_retain(dq); // released in _dispatch_worker_thread
        while ((r = pthread_create(pthr, attr, _dispatch_worker_thread, dq))) {
            if (r != EAGAIN) {
                (void)dispatch_assume_zero(r);
            }
            _dispatch_temporary_resource_shortage();
        }
    } while (--remaining);
#else // defined(_WIN32)
#if DISPATCH_USE_MGR_THREAD && DISPATCH_USE_PTHREAD_ROOT_QUEUES
    if (unlikely(dq == &_dispatch_mgr_root_queue)) {
        _dispatch_mgr_root_queue_init();
    }
#endif
    do {
        _dispatch_retain(dq); // released in _dispatch_worker_thread
#if DISPATCH_DEBUG
        unsigned dwStackSize = 0;
#else
        unsigned dwStackSize = 64 * 1024;
#endif
        uintptr_t hThread = 0;
        while (!(hThread = _beginthreadex(NULL, dwStackSize, _dispatch_worker_thread_thunk, dq, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL))) {
            if (errno != EAGAIN) {
                (void)dispatch_assume(hThread);
            }
            _dispatch_temporary_resource_shortage();
        }
#if DISPATCH_USE_PTHREAD_ROOT_QUEUES
        if (_dispatch_mgr_sched.prio > _dispatch_mgr_sched.default_prio) {
            (void)dispatch_assume_zero(SetThreadPriority((HANDLE)hThread, _dispatch_mgr_sched.prio) == TRUE);
        }
#endif
        CloseHandle((HANDLE)hThread);
    } while (--remaining);
#endif // defined(_WIN32)
#else
    (void)floor;
#endif // DISPATCH_USE_PTHREAD_POOL
}

在這里_dispatch_root_queues_init();有處理dq,比較隱蔽,我們來看下它的代碼,如下:

static inline void
_dispatch_root_queues_init(void)
{
    dispatch_once_f(&_dispatch_root_queues_pred, NULL,
            _dispatch_root_queues_init_once);
}

這里能過單例調(diào)用,后續(xù)會(huì)講單例這塊,這里先暫不提。
我們看下_dispatch_root_queues_init_once這個(gè)函數(shù)代碼:

static void
_dispatch_root_queues_init_once(void *context DISPATCH_UNUSED)
{
    _dispatch_fork_becomes_unsafe();
#if DISPATCH_USE_INTERNAL_WORKQUEUE
    size_t I;
    for (i = 0; i < DISPATCH_ROOT_QUEUE_COUNT; i++) {
        _dispatch_root_queue_init_pthread_pool(&_dispatch_root_queues[i], 0,
                _dispatch_root_queues[i].dq_priority);
    }
#else
    int wq_supported = _pthread_workqueue_supported();
    int r = ENOTSUP;

    if (!(wq_supported & WORKQ_FEATURE_MAINTENANCE)) {
        DISPATCH_INTERNAL_CRASH(wq_supported,
                "QoS Maintenance support required");
    }

#if DISPATCH_USE_KEVENT_SETUP
    struct pthread_workqueue_config cfg = {
        .version = PTHREAD_WORKQUEUE_CONFIG_VERSION,
        .flags = 0,
        .workq_cb = 0,
        .kevent_cb = 0,
        .workloop_cb = 0,
        .queue_serialno_offs = dispatch_queue_offsets.dqo_serialnum,
#if PTHREAD_WORKQUEUE_CONFIG_VERSION >= 2
        .queue_label_offs = dispatch_queue_offsets.dqo_label,
#endif
    };
#endif

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
    if (unlikely(!_dispatch_kevent_workqueue_enabled)) {
#if DISPATCH_USE_KEVENT_SETUP
        cfg.workq_cb = _dispatch_worker_thread2;
        r = pthread_workqueue_setup(&cfg, sizeof(cfg));
#else
        r = _pthread_workqueue_init(_dispatch_worker_thread2,
                offsetof(struct dispatch_queue_s, dq_serialnum), 0);
#endif // DISPATCH_USE_KEVENT_SETUP
#if DISPATCH_USE_KEVENT_WORKLOOP
    } else if (wq_supported & WORKQ_FEATURE_WORKLOOP) {
#if DISPATCH_USE_KEVENT_SETUP
        cfg.workq_cb = _dispatch_worker_thread2;
        cfg.kevent_cb = (pthread_workqueue_function_kevent_t) _dispatch_kevent_worker_thread;
        cfg.workloop_cb = (pthread_workqueue_function_workloop_t) _dispatch_workloop_worker_thread;
        r = pthread_workqueue_setup(&cfg, sizeof(cfg));
#else
        r = _pthread_workqueue_init_with_workloop(_dispatch_worker_thread2,
                (pthread_workqueue_function_kevent_t)
                _dispatch_kevent_worker_thread,
                (pthread_workqueue_function_workloop_t)
                _dispatch_workloop_worker_thread,
                offsetof(struct dispatch_queue_s, dq_serialnum), 0);
#endif // DISPATCH_USE_KEVENT_SETUP
#endif // DISPATCH_USE_KEVENT_WORKLOOP
#if DISPATCH_USE_KEVENT_WORKQUEUE
    } else if (wq_supported & WORKQ_FEATURE_KEVENT) {
#if DISPATCH_USE_KEVENT_SETUP
        cfg.workq_cb = _dispatch_worker_thread2;
        cfg.kevent_cb = (pthread_workqueue_function_kevent_t) _dispatch_kevent_worker_thread;
        r = pthread_workqueue_setup(&cfg, sizeof(cfg));
#else
        r = _pthread_workqueue_init_with_kevent(_dispatch_worker_thread2,
                (pthread_workqueue_function_kevent_t)
                _dispatch_kevent_worker_thread,
                offsetof(struct dispatch_queue_s, dq_serialnum), 0);
#endif // DISPATCH_USE_KEVENT_SETUP
#endif
    } else {
        DISPATCH_INTERNAL_CRASH(wq_supported, "Missing Kevent WORKQ support");
    }
#pragma clang diagnostic pop

    if (r != 0) {
        DISPATCH_INTERNAL_CRASH((r << 16) | wq_supported,
                "Root queue initialization failed");
    }
#endif // DISPATCH_USE_INTERNAL_WORKQUEUE
}

這里_dispatch_root_queue_init_pthread_pool判斷線程的狀況。
cfg.workq_cb = _dispatch_worker_thread2;這里的_dispatch_worker_thread2就是要回調(diào)的對(duì)象,我們可以通過bt,看下堆棧,如圖:

6

_dispatch_worker_thread2是什么時(shí)候調(diào)用,我們接著分析。

_dispatch_worker_thread2的代碼如下:

static void
_dispatch_worker_thread2(pthread_priority_t pp)
{
    bool overcommit = pp & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG;
    dispatch_queue_global_t dq;

    pp &= _PTHREAD_PRIORITY_OVERCOMMIT_FLAG | ~_PTHREAD_PRIORITY_FLAGS_MASK;
    _dispatch_thread_setspecific(dispatch_priority_key, (void *)(uintptr_t)pp);
    dq = _dispatch_get_root_queue(_dispatch_qos_from_pp(pp), overcommit);

    _dispatch_introspection_thread_add();
    _dispatch_trace_runtime_event(worker_unpark, dq, 0);

    int pending = os_atomic_dec2o(dq, dgq_pending, relaxed);
    dispatch_assert(pending >= 0);
    _dispatch_root_queue_drain(dq, dq->dq_priority,
            DISPATCH_INVOKE_WORKER_DRAIN | DISPATCH_INVOKE_REDIRECTING_DRAIN);
    _dispatch_voucher_debug("root queue clear", NULL);
    _dispatch_reset_voucher(NULL, DISPATCH_THREAD_PARK);
    _dispatch_trace_runtime_event(worker_park, NULL, 0);
}

這里_dispatch_root_queue_drain(dq, dq->dq_priority,
DISPATCH_INVOKE_WORKER_DRAIN | DISPATCH_INVOKE_REDIRECTING_DRAIN);
有處理,我們?cè)倏聪逻@個(gè)函數(shù)的代碼:

static void
_dispatch_root_queue_drain(dispatch_queue_global_t dq,
        dispatch_priority_t pri, dispatch_invoke_flags_t flags)
{
#if DISPATCH_DEBUG
    dispatch_queue_t cq;
    if (unlikely(cq = _dispatch_queue_get_current())) {
        DISPATCH_INTERNAL_CRASH(cq, "Premature thread recycling");
    }
#endif
    _dispatch_queue_set_current(dq);
    _dispatch_init_basepri(pri);
    _dispatch_adopt_wlh_anon();

    struct dispatch_object_s *item;
    bool reset = false;
    dispatch_invoke_context_s dic = { };
#if DISPATCH_COCOA_COMPAT
    _dispatch_last_resort_autorelease_pool_push(&dic);
#endif // DISPATCH_COCOA_COMPAT
    _dispatch_queue_drain_init_narrowing_check_deadline(&dic, pri);
    _dispatch_perfmon_start();
    while (likely(item = _dispatch_root_queue_drain_one(dq))) {
        if (reset) _dispatch_wqthread_override_reset();
        _dispatch_continuation_pop_inline(item, &dic, flags, dq);
        reset = _dispatch_reset_basepri_override();
        if (unlikely(_dispatch_queue_drain_should_narrow(&dic))) {
            break;
        }
    }

    // overcommit or not. worker thread
    if (pri & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) {
        _dispatch_perfmon_end(perfmon_thread_worker_oc);
    } else {
        _dispatch_perfmon_end(perfmon_thread_worker_non_oc);
    }

#if DISPATCH_COCOA_COMPAT
    _dispatch_last_resort_autorelease_pool_pop(&dic);
#endif // DISPATCH_COCOA_COMPAT
    _dispatch_reset_wlh();
    _dispatch_clear_basepri();
    _dispatch_queue_set_current(NULL);
}

這行代碼

_dispatch_continuation_pop_inline(item, &dic, flags, dq);

它的代碼如下:

static inline void
_dispatch_continuation_pop_inline(dispatch_object_t dou,
        dispatch_invoke_context_t dic, dispatch_invoke_flags_t flags,
        dispatch_queue_class_t dqu)
{
    dispatch_pthread_root_queue_observer_hooks_t observer_hooks =
            _dispatch_get_pthread_root_queue_observer_hooks();
    if (observer_hooks) observer_hooks->queue_will_execute(dqu._dq);
    flags &= _DISPATCH_INVOKE_PROPAGATE_MASK;
    if (_dispatch_object_has_vtable(dou)) {
        dx_invoke(dou._dq, dic, flags);
    } else {
        _dispatch_continuation_invoke_inline(dou, flags, dqu);
    }
    if (observer_hooks) observer_hooks->queue_did_execute(dqu._dq);
}

這里的_dispatch_continuation_invoke_inline(dou, flags, dqu);調(diào)用了,我們?cè)倏聪滤拇a,如下:

static inline void
_dispatch_continuation_invoke_inline(dispatch_object_t dou,
        dispatch_invoke_flags_t flags, dispatch_queue_class_t dqu)
{
    dispatch_continuation_t dc = dou._dc, dc1;
    dispatch_invoke_with_autoreleasepool(flags, {
        uintptr_t dc_flags = dc->dc_flags;
        // Add the item back to the cache before calling the function. This
        // allows the 'hot' continuation to be used for a quick callback.
        //
        // The ccache version is per-thread.
        // Therefore, the object has not been reused yet.
        // This generates better assembly.
        _dispatch_continuation_voucher_adopt(dc, dc_flags);
        if (!(dc_flags & DC_FLAG_NO_INTROSPECTION)) {
            _dispatch_trace_item_pop(dqu, dou);
        }
        if (dc_flags & DC_FLAG_CONSUME) {
            dc1 = _dispatch_continuation_free_cacheonly(dc);
        } else {
            dc1 = NULL;
        }
        if (unlikely(dc_flags & DC_FLAG_GROUP_ASYNC)) {
            _dispatch_continuation_with_group_invoke(dc);
        } else {
            _dispatch_client_callout(dc->dc_ctxt, dc->dc_func);
            _dispatch_trace_item_complete(dc);
        }
        if (unlikely(dc1)) {
            _dispatch_continuation_free_to_cache_limit(dc1);
        }
    });
    _dispatch_perfmon_workitem_inc();
}

這里的_dispatch_client_callout(dc->dc_ctxt, dc->dc_func);代碼,有拿dc_xtxt和dc_func

我們?cè)俅慰聪?_dispatch_client_callout*這個(gè)函數(shù)的代碼

void
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
    _dispatch_get_tsd_base();
    void *u = _dispatch_get_unwind_tsd();
    if (likely(!u)) return f(ctxt);
    _dispatch_set_unwind_tsd(NULL);
    f(ctxt);
    _dispatch_free_unwind_tsd();
    _dispatch_set_unwind_tsd(u);
}

這里最終調(diào)用執(zhí)行block。

結(jié)語

這篇文章我們介紹了GCD的基本概念,函數(shù)與隊(duì)列的情況,主隊(duì)列分析,GCD底層源碼繼承鏈,GCD的任務(wù)執(zhí)行堆棧(同步)流程,GCD的任務(wù)執(zhí)行堆棧(異步)流程,GCD的原理分析,還未分析完,將會(huì)再下篇文章再次介紹GCD的有關(guān)知識(shí),錯(cuò)誤之處,請(qǐng)大家指正。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容