iOS 底層探索:多線程GCD底層探索(上)

iOS 底層探索: 學(xué)習(xí)大綱 OC篇

前言

  • 上篇我們復(fù)習(xí)了常用的GCD之后贞瞒,我們會(huì)問(wèn)dispatch_async是如何開啟線程的呢?帶著這個(gè)疑問(wèn),我們開啟GCD 底層源碼的研究。
  • 主要內(nèi)容:探索隊(duì)列的本質(zhì),隊(duì)列的創(chuàng)建糯景,串行和并發(fā) 、同步和異步執(zhí)行的區(qū)別及底層執(zhí)行流程省骂。

準(zhǔn)備

一 蟀淮、查找 GCD 源碼

來(lái)到工程,我們跳轉(zhuǎn)查看dispatch_async如下:只是提供了一個(gè)對(duì)外的接口钞澳。

#ifdef __BLOCKS__
API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
void
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
#endif

所以我們?cè)偃帱c(diǎn)調(diào)試:


我們?cè)?code>dispatch_async下斷點(diǎn)灭贷,查看堆棧下的dispatch_async,就會(huì)來(lái)到匯編調(diào)用情況略贮,其中我們可以看到libdispatch.dylib 調(diào)用了dispatch_async:甚疟,所以根據(jù)以前的經(jīng)驗(yàn),GCD的庫(kù)就在libdispatch.dylib 里面.所以我們?nèi)ピ创a中查看. 下載地址上面已給出逃延。

二 览妖、libdispatch源碼分析

當(dāng)我翻開源碼的時(shí)候,首先我發(fā)現(xiàn)揽祥,沒(méi)法編譯這份源碼讽膏,其次源碼中結(jié)構(gòu)體、方法等的命名不能從字面理解拄丰,各種宏定義的嵌套錯(cuò)綜復(fù)雜府树,所以看了半天有點(diǎn)讀不下去了俐末。但是,雖然不能像以前探索objc源碼那樣通過(guò)LLDB調(diào)試驗(yàn)證奄侠,但是我們可以從我們使用GCD流程下手卓箫,刨根問(wèn)底,抱著探索求真的目的垄潮,順著思路往下慢慢的找關(guān)鍵代碼烹卒,然后進(jìn)行分析其流程。

所以我們開始第一階段的探索:

在上一篇講解了GCD的使用步驟:

  • 第一步:創(chuàng)建一個(gè)隊(duì)列(串行隊(duì)列或并發(fā)隊(duì)列)
  • 第二步:將任務(wù)追加到任務(wù)的等待隊(duì)列中弯洗,然后系統(tǒng)就會(huì)根據(jù)任務(wù)類型執(zhí)行任務(wù)(同步執(zhí)行或異步執(zhí)行)

隊(duì)列類型 dispatch_queue_t
隊(duì)列的創(chuàng)建方法:dispatch_queue_create

創(chuàng)建串行隊(duì)列
dispatch_queue_t queue = 
dispatch_queue_create("com.lgcooci.seial", DISPATCH_QUEUE_SERIAL);
創(chuàng)建并發(fā)隊(duì)列
dispatch_queue_t queue = 
dispatch_queue_create("com.lgcooci.concurrent", DISPATCH_QUEUE_CONCURRENT);

首先我們?cè)谠创a中全局去搜索找找dispatch_queue_t是什么旅急?

1. 隊(duì)列類型dispatch_queue_t

首先可以看到dispatch_queue_t本身只是dispatch_queue_s這個(gè)結(jié)構(gòu)體指針

typedef struct dispatch_queue_s *dispatch_queue_t; 

繼續(xù)查找dispatch_queue_s定義

struct dispatch_queue_s {
    DISPATCH_QUEUE_CLASS_HEADER(queue, void *__dq_opaque1);
    /* 32bit hole on LP64 */
} DISPATCH_ATOMIC64_ALIGN;

繼續(xù)查找DISPATCH_QUEUE_CLASS_HEADER ,發(fā)現(xiàn)是個(gè)如下

#define DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__) \
    _DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__); \
    /* LP64 global queue cacheline boundary */ \
    unsigned long dq_serialnum; \// queue的編號(hào)
    const char *dq_label; \   //標(biāo)簽
    DISPATCH_UNION_LE(uint32_t volatile dq_atomic_flags, \
        const uint16_t dq_width, \
        const uint16_t __dq_opaque2 \
    ); \
    dispatch_priority_t dq_priority; \//優(yōu)先級(jí)
    union { \
        struct dispatch_queue_specific_head_s *dq_specific_head; \
        struct dispatch_source_refs_s *ds_refs; \
        struct dispatch_timer_source_refs_s *ds_timer_refs; \
        struct dispatch_mach_recv_refs_s *dm_recv_refs; \
        struct dispatch_channel_callbacks_s const *dch_callbacks; \
    }; \
    int volatile dq_sref_cnt

在這個(gè)宏里我們找到相關(guān)的方法_DISPATCH_QUEUE_CLASS_HEADER(x, pointer_sized_field); 繼續(xù)展開搜索查看里面的內(nèi)容如下:

// 展開_DISPATCH_QUEUE_CLASS_HEADER

#define _DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__) \
    DISPATCH_OBJECT_HEADER(x); \
    DISPATCH_UNION_LE(uint64_t volatile dq_state, \
            dispatch_lock dq_state_lock, \
            uint32_t dq_state_bits \
    ); \

// 持續(xù)展開DISPATCH_OBJECT_HEADER

#define DISPATCH_OBJECT_HEADER(x) \
    struct dispatch_object_s _as_do[0]; \
    _DISPATCH_OBJECT_HEADER(x)
    
// 進(jìn)一步查看 _DISPATCH_OBJECT_HEADER

#define _DISPATCH_OBJECT_HEADER(x) \
    struct _os_object_s _as_os_obj[0]; \
    OS_OBJECT_STRUCT_HEADER(dispatch_##x); \  // 這個(gè)宏牡整,可以理解為dispatch_object_s繼承自_os_object_s
    struct dispatch_##x##_s *volatile do_next; \
    struct dispatch_queue_s *do_targetq; \
    void *do_ctxt; \
    void *do_finalizer
    

來(lái)到OS_OBJECT_STRUCT_HEADER之后藐吮,我們需要注意一個(gè)成員變量,記住這個(gè)成員變量名字叫做do_vtable逃贝。再繼續(xù)拆解_OS_OBJECT_HEADER發(fā)現(xiàn)里面起就是一個(gè)isa指針引用計(jì)數(shù)一些信息炎码。

再查看 OS_OBJECT_STRUCT_HEADER

#define OS_OBJECT_STRUCT_HEADER(x) \
    _OS_OBJECT_HEADER(\
    const void *_objc_isa, \
    do_ref_cnt, \
    do_xref_cnt); \
// 注意這個(gè)成員變量,后面將任務(wù)Push到隊(duì)列就是通過(guò)這個(gè)變量
    const struct x##_vtable_s *do_vtable
    
// 進(jìn)一步查看 _OS_OBJECT_HEADER

#define _OS_OBJECT_HEADER(isa, ref_cnt, xref_cnt) \
        isa; /* must be pointer-sized */ \ // isa指針
        int volatile ref_cnt; \ // gcd對(duì)象內(nèi)部引用計(jì)數(shù)
        int volatile xref_cnt// gcd對(duì)象外部引用計(jì)數(shù)(內(nèi)外部都要減到0時(shí)秋泳,對(duì)象會(huì)被釋放)

經(jīng)過(guò)一步步相關(guān)代碼的查找最終來(lái)到_OS_OBJECT_HEADER ,可以發(fā)現(xiàn)這些代碼晦澀難懂,但是我們研究源碼不一定要知道每句代碼的意思攒菠,我們查看其核心內(nèi)容:dispatch_queue_t 的本質(zhì)是一個(gè)結(jié)構(gòu)體指針對(duì)象迫皱,里面包含了label(標(biāo)簽)、priority(優(yōu)先級(jí))等一些信息辖众。dispatch_queue_t類型的指針卓起,指向一個(gè)dispatch_queue_s 類型的結(jié)構(gòu)體。

其實(shí)GCD源碼中的數(shù)據(jù)結(jié)構(gòu)為dispatch_object_t聯(lián)合抽象類

typedef union {
    struct _os_object_s *_os_obj;// 基類
    struct dispatch_object_s *_do;// 基類繼承os_object
    struct dispatch_queue_s *_dq;// 隊(duì)列結(jié)構(gòu)
    struct dispatch_queue_attr_s *_dqa;// 隊(duì)列相關(guān)屬性
    struct dispatch_group_s *_dg;// group結(jié)構(gòu)
    struct dispatch_source_s *_ds;
    struct dispatch_channel_s *_dch;
    struct dispatch_mach_s *_dm;
    struct dispatch_mach_msg_s *_dmsg;
    struct dispatch_semaphore_s *_dsema;// 信號(hào)量
    struct dispatch_data_s *_ddata;
    struct dispatch_io_s *_dchannel;
} dispatch_object_t DISPATCH_TRANSPARENT_UNION;

2. 創(chuàng)建隊(duì)列 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);
}

label : 標(biāo)簽凹炸,我們平時(shí)傳入隊(duì)列的名字
attr :我們知道創(chuàng)建隊(duì)列時(shí)戏阅, attr 屬性有三個(gè)值可選,nil啤它、DISPATCH_QUEUE_SERIAL(實(shí)際上就是 nil) 或 DISPATCH_QUEUE_CONCURRENT奕筐。

_dispatch_queue_create_with_target函數(shù),這里會(huì)創(chuàng)建一個(gè)root隊(duì)列,并將自己新建的隊(duì)列綁定到所對(duì)應(yīng)的root隊(duì)列上变骡。

DISPATCH_NOINLINE
static dispatch_queue_t
_dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
        dispatch_queue_t tq, bool legacy)
{
    dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);

    //
    // Step 1: Normalize arguments (qos, overcommit, tq) 規(guī)范化參數(shù)
    //
    // 根據(jù)上文代碼注釋里提到的离赫,作者認(rèn)為調(diào)用者傳入DISPATCH_QUEUE_SERIAL和nil的幾率要大于傳DISPATCH_QUEUE_CONCURRENT。所以這里設(shè)置個(gè)默認(rèn)值塌碌。
    // 這里怎么理解呢渊胸?只要看做if(!dqa)即可
    if (!slowpath(dqa)) {
        // _dispatch_get_default_queue_attr里面會(huì)將dqa的dqa_autorelease_frequency指定為DISPATCH_AUTORELEASE_FREQUENCY_INHERIT的,inactive也指定為false台妆。這里就不展開了翎猛,只需要知道賦了哪些值胖翰。因?yàn)楹竺鏁?huì)用到。
        dqa = _dispatch_get_default_queue_attr();
    } else if (dqa->do_vtable != DISPATCH_VTABLE(queue_attr)) {
        DISPATCH_CLIENT_CRASH(dqa->do_vtable, "Invalid queue attribute");
    }

    // 取出優(yōu)先級(jí)
    dispatch_qos_t qos = _dispatch_priority_qos(dqa->dqa_qos_and_relpri);

    // overcommit單純從英文理解表示過(guò)量使用的意思切厘,那這里這個(gè)overcommit就是一個(gè)標(biāo)識(shí)符萨咳,表示是不是就算負(fù)荷很高了,但還是得給我新開一個(gè)線程出來(lái)給我執(zhí)行任務(wù)迂卢。
    _dispatch_queue_attr_overcommit_t overcommit = dqa->dqa_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");
        }
    }

    // 如果overcommit沒(méi)有被指定
    if (overcommit == _dispatch_queue_attr_overcommit_unspecified) {
         // 所以對(duì)于overcommit某弦,如果是串行的話默認(rèn)是開啟的,而并行是關(guān)閉的
        overcommit = dqa->dqa_concurrent ?
                _dispatch_queue_attr_overcommit_disabled :
                _dispatch_queue_attr_overcommit_enabled;
    }

    // 之前說(shuō)過(guò)初始化隊(duì)列默認(rèn)傳了DISPATCH_TARGET_QUEUE_DEFAULT而克,也就是null靶壮,所以進(jìn)入if語(yǔ)句。
    if (!tq) {
        // 獲取一個(gè)管理自己隊(duì)列的root隊(duì)列员萍。
        tq = _dispatch_get_root_queue(
                qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos,
                overcommit == _dispatch_queue_attr_overcommit_enabled);
        if (slowpath(!tq)) {
            DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
        }
    }

//  -----------  開始進(jìn)行隊(duì)列的創(chuàng)建   -----------------

    // legacy默認(rèn)是true的
    if (legacy) {
        // 之前說(shuō)過(guò)腾降,默認(rèn)是會(huì)給dqa_autorelease_frequency指定為DISPATCH_AUTORELEASE_FREQUENCY_INHERIT,所以這個(gè)判斷式是成立的
        if (dqa->dqa_inactive || dqa->dqa_autorelease_frequency) {
            legacy = false;
        }
    }
// vtable變量很重要碎绎,之后會(huì)被賦值到之前說(shuō)的dispatch_queue_t結(jié)構(gòu)體里的do_vtable變量上
    const void *vtable;
    dispatch_queue_flags_t dqf = legacy ? DQF_MUTABLE : 0;
    if (dqai.dqai_concurrent) {
// 如果創(chuàng)建隊(duì)列的時(shí)候傳了DISPATCH_QUEUE_CONCURRENT螃壤,就是走這里
        vtable = DISPATCH_VTABLE(queue_concurrent);
    } else {
        // 如果創(chuàng)建線程沒(méi)有指定為并行隊(duì)列,無(wú)論你傳DISPATCH_QUEUE_SERIAL還是nil筋帖,都會(huì)創(chuàng)建一個(gè)串行隊(duì)列奸晴。
        vtable = DISPATCH_VTABLE(queue_serial);
    }
    switch (dqai.dqai_autorelease_frequency) {
             .....
    }
     if (label) {
        // 判斷傳進(jìn)來(lái)的字符串是否可變的,如果可變的copy成一份不可變的
        const char *tmp = _dispatch_strdup_if_mutable(label);
        if (tmp != label) {
            dqf |= DQF_LABEL_NEEDS_FREE;
            label = tmp;
        }
    }


   // _dispatch_object_alloc里面就將vtable賦值給do_vtable變量上了日麸。
    dispatch_lane_t dq = _dispatch_object_alloc(vtable,
            sizeof(struct dispatch_lane_s));
   // 第三個(gè)參數(shù)根據(jù)是否并行隊(duì)列寄啼,如果不是則最多開一個(gè)線程,如果是則最多開0x1000 - 2個(gè)線程代箭,這個(gè)數(shù)量很驚人了已經(jīng),換成十進(jìn)制就是(4096 - 2)個(gè)墩划。
    // dqa_inactive之前說(shuō)串行是false的
    // DISPATCH_QUEUE_ROLE_INNER 也是0,所以這里串行隊(duì)列的話dqa->dqa_state是0
    _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);
   // 自定義的queue的目標(biāo)隊(duì)列是root隊(duì)列
    dq->do_targetq = tq;
    _dispatch_object_debug(dq, "%s", __func__);
    return _dispatch_trace_queue_create(dq)._dq;
}

源碼中大部分代碼都不能從字面上了解其意思嗡综,但是這里有幾個(gè)重要的函數(shù)我們可以找到乙帮,首先是創(chuàng)建一個(gè)root隊(duì)列_dispatch_get_root_queue函數(shù)。取root隊(duì)列

static inline dispatch_queue_global_t
_dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit)
{
    if (unlikely(qos < DISPATCH_QOS_MIN || qos > DISPATCH_QOS_MAX)) {
        DISPATCH_CLIENT_CRASH(qos, "Corrupted priority");
    }
    return &_dispatch_root_queues[2 * (qos - 1) + overcommit];
}

看下這個(gè)_dispatch_root_queues數(shù)組极景。我們可以看到察净,每一個(gè)優(yōu)先級(jí)都有對(duì)應(yīng)的root隊(duì)列,每一個(gè)優(yōu)先級(jí)又分為是不是可以過(guò)載的隊(duì)列盼樟。

// 6618342 Contact the team that owns the Instrument DTrace probe before
//         renaming this symbol
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_GLOBAL_OBJECT_HEADER(queue_root)塞绿,解析到最后是OSdispatch##name##_class這樣的這樣的,對(duì)應(yīng)的實(shí)例對(duì)象是如下代碼恤批,指定了root隊(duì)列各個(gè)操作對(duì)應(yīng)的函數(shù)异吻。

可以看到很熟悉的alloc 、init 操作了;
_dispatch_object_alloc: 申請(qǐng)對(duì)應(yīng)類型的內(nèi)存;
_dispatch_queue_init:初始化诀浪。

首先看前者的實(shí)現(xiàn):

// 注意對(duì)于iOS并不滿足 OS_OBJECT_HAVE_OBJC1
void *
_dispatch_object_alloc(const void *vtable, size_t size)
{
#if OS_OBJECT_HAVE_OBJC1
    const struct dispatch_object_vtable_s *_vtable = vtable;
    dispatch_object_t dou;
    dou._os_obj = _os_object_alloc_realized(_vtable->_os_obj_objc_isa, size);
    dou._do->do_vtable = vtable;
    return dou._do;
#else
    return _os_object_alloc_realized(vtable, size);
#endif
}

// 接著看 _os_object_alloc_realized
inline _os_object_t
_os_object_alloc_realized(const void *cls, size_t size)
{
    _os_object_t obj;
    dispatch_assert(size >= sizeof(struct _os_object_s));
    while (unlikely(!(obj = calloc(1u, size)))) {
        _dispatch_temporary_resource_shortage();
    }
    obj->os_obj_isa = cls;
    return obj;
}

再看一下 _os_objc_alloc


_os_object_t
_os_object_alloc(const void *cls, size_t size)
{
    if (!cls) cls = &_os_object_vtable;
    return _os_object_alloc_realized(cls, size);
}

inline _os_object_t
_os_object_alloc_realized(const void *cls, size_t size)
{
    _os_object_t obj;
    dispatch_assert(size >= sizeof(struct _os_object_s));
    while (unlikely(!(obj = calloc(1u, size)))) {
        _dispatch_temporary_resource_shortage();
    }
    obj->os_obj_isa = cls;
    return obj;
}

返回值類型:結(jié)構(gòu)體_os_object_s

typedef struct _os_object_s {
    _OS_OBJECT_HEADER(
    const _os_object_vtable_s *os_obj_isa,
    os_obj_ref_cnt,
    os_obj_xref_cnt);
} _os_object_s;


// 系統(tǒng)對(duì)象頭部定義宏
#define _OS_OBJECT_HEADER(isa, ref_cnt, xref_cnt) 
        isa;    // isa指針
        int volatile ref_cnt; // gcd對(duì)象內(nèi)部引用計(jì)數(shù)
        int volatile xref_cnt // gcd對(duì)象外部引用計(jì)數(shù)(內(nèi)外部都要減到0時(shí)棋返,對(duì)象會(huì)被釋放)

再看下_dispatch_queue_init函數(shù),這里也就是做些初始化工作了

static inline void _dispatch_queue_init(dispatch_queue_t dq, dispatch_queue_flags_t dqf,
        uint16_t width, uint64_t initial_state_bits)
{
    uint64_t dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(width);

    dispatch_assert((initial_state_bits & ~(DISPATCH_QUEUE_ROLE_MASK |
            DISPATCH_QUEUE_INACTIVE)) == 0);

    if (initial_state_bits & DISPATCH_QUEUE_INACTIVE) {
        dq_state |= DISPATCH_QUEUE_INACTIVE + DISPATCH_QUEUE_NEEDS_ACTIVATION;
        dq_state |= DLOCK_OWNER_MASK;
        dq->do_ref_cnt += 2; 
    }

    dq_state |= (initial_state_bits & DISPATCH_QUEUE_ROLE_MASK);
    // 指向DISPATCH_OBJECT_LISTLESS是優(yōu)化編譯器的作用雷猪。只是為了生成更好的指令讓CPU更好的編碼
    dq->do_next = (struct dispatch_queue_s *)DISPATCH_OBJECT_LISTLESS;
    dqf |= DQF_WIDTH(width);
    // dqf 保存進(jìn) dq->dq_atomic_flags
    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);
}

??最后是_dispatch_introspection_queue_create函數(shù)睛竣,一個(gè)內(nèi)省函數(shù)。

dispatch_queue_t _dispatch_introspection_queue_create(dispatch_queue_t dq)
{
    TAILQ_INIT(&dq->diq_order_top_head);
    TAILQ_INIT(&dq->diq_order_bottom_head);
    _dispatch_unfair_lock_lock(&_dispatch_introspection.queues_lock);
    TAILQ_INSERT_TAIL(&_dispatch_introspection.queues, dq, diq_list);
    _dispatch_unfair_lock_unlock(&_dispatch_introspection.queues_lock);

    DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_create, dq);
    if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_create)) {
        _dispatch_introspection_queue_create_hook(dq);
    }
    return dq;
}

至此求摇,一個(gè)隊(duì)列的創(chuàng)建過(guò)程我們大致了解了射沟。大致可以分為這么幾點(diǎn)

    1. 設(shè)置隊(duì)列優(yōu)先級(jí)
    1. 默認(rèn)創(chuàng)建的是一個(gè)串行隊(duì)列
    1. 設(shè)置隊(duì)列掛載的根隊(duì)列。優(yōu)先級(jí)不同根隊(duì)列也不同
    1. 實(shí)例化vtable對(duì)象与境,這個(gè)對(duì)象給不同隊(duì)列指定了push验夯、wakeup等函數(shù)。

3. 任務(wù)異步dispatch_async

內(nèi)部就是兩個(gè)函數(shù):

  • _dispatch_continuation_init:任務(wù)包裝函數(shù)

  • _dispatch_continuation_async:并發(fā)處理函數(shù)

dispatch_async(dispatch_queue_t dq, dispatch_block_t work)
{
    dispatch_continuation_t dc = _dispatch_continuation_alloc();
    uintptr_t dc_flags = DC_FLAG_CONSUME; // 設(shè)置標(biāo)識(shí)位
    dispatch_qos_t qos;
 // 任務(wù)的包裝器  接收 保存 函數(shù)式 保存block
    qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);
    _dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}

dispatch_continuation_init函數(shù)只是一個(gè)初始化摔刁,主要就是保存Block上下文挥转,指定block的執(zhí)行函數(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)
{
    // block對(duì)象賦值到dc_ctx
    void *ctxt = _dispatch_Block_copy(work); //拷貝任務(wù)
    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);/封裝work - 異步回調(diào)
    if (dc_flags & DC_FLAG_CONSUME) {
        func = _dispatch_call_block_and_release;//回調(diào)函數(shù)賦值 - 同步回調(diào)
    }
    return _dispatch_continuation_init_f(dc, dqu, ctxt, func, flags, dc_flags);
}

_dispatch_call_block_and_release這個(gè)函數(shù)就是直接執(zhí)行block了,所以dc->dc_func被調(diào)用的話就block會(huì)被直接執(zhí)行了共屈。

void
_dispatch_call_block_and_release(void *block)
{
    void (^b)(void) = block;
    b();
    Block_release(b);
}

上面的初始化過(guò)程就是這樣绑谣,接著看下_dispatch_continuation_async函數(shù)

_dispatch_continuation_async(dispatch_queue_class_t dqu,
        dispatch_continuation_t dc, dispatch_qos_t qos, uintptr_t dc_flags)
{
// 如果是用barrier插進(jìn)來(lái)的任務(wù)或者是串行隊(duì)列,直接將任務(wù)加入到隊(duì)列
#if DISPATCH_INTROSPECTION
    if (!(dc_flags & DC_FLAG_NO_INTROSPECTION)) {
        _dispatch_trace_item_push(dqu, dc); 
//trace 軌跡 跟蹤器的意思  
    }
#else
    (void)dc_flags;
#endif
    return dx_push(dqu._dq, dc, qos);//宏
}

宏:#define dx_push(x, y, z) dx_vtable(x)->dq_push(x, y, z)拗引,我們只關(guān)心dq_push

全局搜索我們看到:

DISPATCH_VTABLE_INSTANCE(queue,
    // This is the base class for queues, no objects of this type are made
    .do_type        = _DISPATCH_QUEUE_CLUSTER,
    .do_dispose     = _dispatch_object_no_dispose,
    .do_debug       = _dispatch_queue_debug,
    .do_invoke      = _dispatch_object_no_invoke,

    .dq_activate    = _dispatch_queue_no_activate,
);

DISPATCH_VTABLE_INSTANCE(workloop,
    .do_type        = DISPATCH_WORKLOOP_TYPE,
    .do_dispose     = _dispatch_workloop_dispose,
    .do_debug       = _dispatch_queue_debug,
    .do_invoke      = _dispatch_workloop_invoke,

    .dq_activate    = _dispatch_queue_no_activate,
    .dq_wakeup      = _dispatch_workloop_wakeup,
    .dq_push        = _dispatch_workloop_push,
);

DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_serial, lane,
    .do_type        = DISPATCH_QUEUE_SERIAL_TYPE,
    .do_dispose     = _dispatch_lane_dispose,
    .do_debug       = _dispatch_queue_debug,
    .do_invoke      = _dispatch_lane_invoke,

    .dq_activate    = _dispatch_lane_activate,
    .dq_wakeup      = _dispatch_lane_wakeup,
    .dq_push        = _dispatch_lane_push,
);

DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_concurrent, lane,
    .do_type        = DISPATCH_QUEUE_CONCURRENT_TYPE,
    .do_dispose     = _dispatch_lane_dispose,
    .do_debug       = _dispatch_queue_debug,
    .do_invoke      = _dispatch_lane_invoke,

    .dq_activate    = _dispatch_lane_activate,
    .dq_wakeup      = _dispatch_lane_wakeup,
    .dq_push        = _dispatch_lane_concurrent_push,
);

根據(jù)隊(duì)列的類型不同借宵,這里會(huì)對(duì)應(yīng)的有不同的方法
比如:
并發(fā)隊(duì)列:.dq_push = _dispatch_lane_concurrent_push,
串行隊(duì)列:.dq_push = _dispatch_lane_push,
等等
在項(xiàng)目中我們可以添加符號(hào)斷點(diǎn)_dispatch_lane_concurrent_push驗(yàn)證如下:

image.png

所以我們先研究下:_dispatch_lane_concurrent_push

void
_dispatch_lane_concurrent_push(dispatch_lane_t dq, dispatch_object_t dou,
        dispatch_qos_t qos)
{
    if (dq->dq_items_tail == NULL &&
            !_dispatch_object_is_waiter(dou) &&
            !_dispatch_object_is_barrier(dou) &&
            _dispatch_queue_try_acquire_async(dq)) {
// 進(jìn)行一系列的判斷后,進(jìn)入該方法矾削。
        return _dispatch_continuation_redirect_push(dq, dou, qos);
    }

    _dispatch_lane_push(dq, dou, qos);
}

符號(hào)斷點(diǎn)調(diào)試可以發(fā)現(xiàn)會(huì)走_dispatch_continuation_redirect_push 這里:

DISPATCH_NOINLINE
static void
_dispatch_continuation_redirect_push(dispatch_lane_t dl,
        dispatch_object_t dou, dispatch_qos_t qos)
{
    if (likely(!_dispatch_object_is_redirection(dou))) {
        dou._dc = _dispatch_async_redirect_wrap(dl, dou);
    } else if (!dou._dc->dc_ctxt) {
        // find first queue in descending target queue order that has
        // an autorelease frequency set, and use that as the frequency for
        // this continuation.
        dou._dc->dc_ctxt = (void *)
        (uintptr_t)_dispatch_queue_autorelease_frequency(dl);
    }

    dispatch_queue_t dq = dl->do_targetq;
    if (!qos) qos = _dispatch_priority_qos(dq->dq_priority);
    // 遞歸調(diào)用壤玫,
    // 原因在于GCD也是對(duì)象,也存在繼承封裝的問(wèn)題怔软,類似于 類 父類 根類的關(guān)系。
    dx_push(dq, dou, qos);
}

這里會(huì)發(fā)現(xiàn)又走到了dx_push择镇,即遞歸了挡逼,綜合前面隊(duì)列創(chuàng)建時(shí)可知,隊(duì)列也是一個(gè)對(duì)象腻豌,有父類家坎、根類,所以會(huì)遞歸執(zhí)行到根類的方法

接下來(lái)吝梅,通過(guò)根類的_dispatch_root_queue_push符號(hào)斷點(diǎn)虱疏,來(lái)驗(yàn)證猜想是否正確,從運(yùn)行結(jié)果看出苏携,完全是正確的

進(jìn)入_dispatch_root_queue_push -> _dispatch_root_queue_push_inline ->_dispatch_root_queue_poke -> _dispatch_root_queue_poke_slow源碼做瞪,經(jīng)過(guò)符號(hào)斷點(diǎn)驗(yàn)證,確實(shí)是走的這里,查看該方法的源碼實(shí)現(xiàn)装蓬,主要有兩步操作

通過(guò)_dispatch_root_queues_init方法注冊(cè)回調(diào)

通過(guò)do-while循環(huán)創(chuàng)建線程著拭,使用pthread_create方法

DISPATCH_NOINLINE
static void
_dispatch_root_queue_poke_slow(dispatch_queue_global_t dq, int n, int floor)
{
    int remaining = n;
    int r = ENOSYS;

    _dispatch_root_queues_init();//重點(diǎn)
    
    ...
    //do-while循環(huán)創(chuàng)建線程
    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);
    ...
}

首先我們先分析一下:_dispatch_root_queues_init

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

進(jìn)入_dispatch_root_queues_init源碼實(shí)現(xiàn),發(fā)現(xiàn)是一個(gè)dispatch_once_f單例(這里不作說(shuō)明,以后重點(diǎn)分析)牍帚,其中傳入的func是_dispatch_root_queues_init_once儡遮。

_dispatch_root_queues_init_once 開始進(jìn)入底層os的處理了。通過(guò)斷點(diǎn)暗赶,bt打印堆棧信息如下:

(lldb) bt
* thread #7, queue = 'cooci', stop reason = breakpoint 1.1
  * frame #0: 0x0000000100449144 001---函數(shù)與隊(duì)列`__29-[ViewController viewDidLoad]_block_invoke(.block_descriptor=0x000000010044c0e0) at ViewController.m:48:9
    frame #1: 0x00000001004efb68 libdispatch.dylib`_dispatch_call_block_and_release + 32
    frame #2: 0x00000001004f15f0 libdispatch.dylib`_dispatch_client_callout + 20
    frame #3: 0x00000001004f44e4 libdispatch.dylib`_dispatch_continuation_pop + 584
    frame #4: 0x00000001004f3888 libdispatch.dylib`_dispatch_async_redirect_invoke + 692
    frame #5: 0x00000001005042ec libdispatch.dylib`_dispatch_root_queue_drain + 364
    frame #6: 0x0000000100504c94 libdispatch.dylib`_dispatch_worker_thread2 + 140
    frame #7: 0x00000001d52b48cc libsystem_pthread.dylib`_pthread_wqthread + 216
(lldb) 

綜上所述鄙币,異步函數(shù)的底層分析如下

【準(zhǔn)備工作】:首先,將異步任務(wù)拷貝并封裝蹂随,并設(shè)置回調(diào)函數(shù)func

【block回調(diào)】:底層通過(guò)dx_push遞歸十嘿,會(huì)重定向到根隊(duì)列,然后通過(guò)pthread_creat創(chuàng)建線程糙及,最后通過(guò)dx_invoke執(zhí)行block回調(diào)(注意dx_push 和 dx_invoke 是成對(duì)的)

異步函數(shù)的底層分析流程如圖所示


4. 任務(wù)同步dispatch_sync

dispatch_sync直接調(diào)用的是dispatch_sync_f

void dispatch_sync(dispatch_queue_t dq, dispatch_block_t work)
{
    // 很大可能不會(huì)走if分支详幽,看做if(_dispatch_block_has_private_data(work))
    if (unlikely(_dispatch_block_has_private_data(work))) {
        return _dispatch_sync_block_with_private_data(dq, work, 0);
    }
    dispatch_sync_f(dq, work, _dispatch_Block_invoke(work));
}

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

查看_dispatch_sync_f_inline源碼,其中width = 1表示是串行隊(duì)列浸锨,其中有兩個(gè)重點(diǎn):

  • 柵欄:_dispatch_barrier_sync_f(可以通過(guò)后文的柵欄函數(shù)底層分析解釋)唇聘,可以得出同步函數(shù)的底層實(shí)現(xiàn)其實(shí)是同步柵欄函數(shù)
  • 死鎖:_dispatch_sync_f_slow,如果存在相互等待的情況柱搜,就會(huì)造成死鎖
static inline void
_dispatch_sync_f_inline(dispatch_queue_t dq, void *ctxt,
        dispatch_function_t func, uintptr_t dc_flags)
{
// 串行隊(duì)列會(huì)走到這個(gè)if分支
    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

// 全局獲取的并行隊(duì)列或者綁定的是非調(diào)度線程的隊(duì)列會(huì)走進(jìn)這個(gè)if分支
    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)));
}

第一種情況迟郎,串行隊(duì)列:dispatch_barrier_sync_f

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

DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_barrier_sync_f_inline(dispatch_queue_t dq, void *ctxt,
        dispatch_function_t func, uintptr_t dc_flags)
{
    dispatch_tid tid = _dispatch_tid_self();

 // 隊(duì)列綁定的是非調(diào)度線程就會(huì)走這里
    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;
    
    if (unlikely(!_dispatch_queue_try_acquire_barrier_sync(dl, tid))) {
        return _dispatch_sync_f_slow(dl, ctxt, func, DC_FLAG_BARRIER, dl,
                DC_FLAG_BARRIER | dc_flags);
    }

    if (unlikely(dl->do_targetq->do_targetq)) {
        return _dispatch_sync_recurse(dl, ctxt, func,
                DC_FLAG_BARRIER | dc_flags);
    }
    _dispatch_introspection_sync_begin(dl);
// 一般會(huì)走到這里
    _dispatch_lane_barrier_sync_invoke_and_complete(dl, ctxt, func
            DISPATCH_TRACE_ARG(_dispatch_trace_item_sync_push_pop(
                    dq, ctxt, func, dc_flags | DC_FLAG_BARRIER)));
}


DISPATCH_NOINLINE
static void
_dispatch_lane_barrier_sync_invoke_and_complete(dispatch_lane_t dq,
        void *ctxt, dispatch_function_t func DISPATCH_TRACE_ARG(void *dc))
{
// 首先會(huì)執(zhí)行這個(gè)函數(shù)
    _dispatch_sync_function_invoke_inline(dq, ctxt, func);
    _dispatch_trace_item_complete(dc);
    if (unlikely(dq->dq_items_tail || dq->dq_width > 1)) {
// 內(nèi)部其實(shí)就是喚醒隊(duì)列
        return _dispatch_lane_barrier_complete(dq, 0, 0);
    }

    const uint64_t fail_unlock_mask = DISPATCH_QUEUE_SUSPEND_BITS_MASK |
            DISPATCH_QUEUE_ENQUEUED | DISPATCH_QUEUE_DIRTY |
            DISPATCH_QUEUE_RECEIVED_OVERRIDE | DISPATCH_QUEUE_SYNC_TRANSFER |
            DISPATCH_QUEUE_RECEIVED_SYNC_WAIT;
    uint64_t old_state, new_state;

    // similar to _dispatch_queue_drain_try_unlock
   // 原子鎖。檢查dq->dq_state與old_state是否相等聪蘸,如果相等把new_state賦值給dq->dq_state宪肖,如果不相等,把dq_state賦值給old_state健爬。
    // 串行隊(duì)列走到這里控乾,dq->dq_state與old_state是相等的,會(huì)把new_state也就是閉包里的賦值的值給dq->dq_state
   
    os_atomic_rmw_loop2o(dq, dq_state, old_state, new_state, release, {
        new_state  = old_state - DISPATCH_QUEUE_SERIAL_DRAIN_OWNED;
        new_state &= ~DISPATCH_QUEUE_DRAIN_UNLOCK_MASK;
        new_state &= ~DISPATCH_QUEUE_MAX_QOS_MASK;
        if (unlikely(old_state & fail_unlock_mask)) {
            os_atomic_rmw_loop_give_up({
                return _dispatch_lane_barrier_complete(dq, 0, 0);
            });
        }
    });
    if (_dq_state_is_base_wlh(old_state)) {
        _dispatch_event_loop_assert_not_owned((dispatch_wlh_t)dq);
    }
}

自定義并行隊(duì)列會(huì)走_(dá)dispatch_sync_invoke_and_complete函數(shù)娜遵。

DISPATCH_NOINLINE
static void
_dispatch_sync_invoke_and_complete(dispatch_lane_t dq, void *ctxt,
        dispatch_function_t func DISPATCH_TRACE_ARG(void *dc))
{
    _dispatch_sync_function_invoke_inline(dq, ctxt, func);
    _dispatch_trace_item_complete(dc);
  // 將自定義隊(duì)列加入到root隊(duì)列里去
    // dispatch_async也會(huì)調(diào)用此方法蜕衡,之前我們初始化的時(shí)候會(huì)綁定一個(gè)root隊(duì)列,這里就將我們新建的隊(duì)列交給root隊(duì)列進(jìn)行管理
    
    _dispatch_lane_non_barrier_complete(dq, 0);
}

static inline void _dispatch_sync_function_invoke_inline(dispatch_queue_t dq, void *ctxt,
        dispatch_function_t func)
{
    dispatch_thread_frame_s dtf;
    _dispatch_thread_frame_push(&dtf, dq);
    // 執(zhí)行任務(wù)
    _dispatch_client_callout(ctxt, func);
    _dispatch_perfmon_workitem_inc();
    _dispatch_thread_frame_pop(&dtf);
}

_dispatch_sync_f_slow 死鎖
進(jìn)入_dispatch_sync_f_slow设拟,當(dāng)前的主隊(duì)列是掛起慨仿、阻塞的

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

往一個(gè)隊(duì)列中 加入任務(wù),會(huì)push加入主隊(duì)列纳胧,進(jìn)入_dispatch_trace_item_push

static inline void
_dispatch_trace_item_push(dispatch_queue_class_t dqu, dispatch_object_t _tail)
{
    if (unlikely(DISPATCH_QUEUE_PUSH_ENABLED())) {
        _dispatch_trace_continuation(dqu._dq, _tail._do, DISPATCH_QUEUE_PUSH);
    }

    _dispatch_trace_item_push_inline(dqu._dq, _tail._do);
    _dispatch_introspection_queue_push(dqu, _tail);
}

進(jìn)入DISPATCH_WAIT_FOR_QUEUE镰吆,判斷dq是否為正在等待的隊(duì)列,然后給出一個(gè)狀態(tài)state跑慕,然后將dq的狀態(tài)和當(dāng)前任務(wù)依賴的隊(duì)列進(jìn)行匹配

static void
__DISPATCH_WAIT_FOR_QUEUE__(dispatch_sync_context_t dsc, dispatch_queue_t dq)
{
    uint64_t dq_state = _dispatch_wait_prepare(dq);
    if (unlikely(_dq_state_drain_locked_by(dq_state, dsc->dsc_waiter))) {
        DISPATCH_CLIENT_CRASH((uintptr_t)dq_state,
                "dispatch_sync called on queue "
                "already owned by current thread");
    }
   .....省略 ....
}

進(jìn)入_dq_state_drain_locked_by -> _dispatch_lock_is_locked_by源碼

DISPATCH_ALWAYS_INLINE
static inline bool
_dispatch_lock_is_locked_by(dispatch_lock lock_value, dispatch_tid tid)
{
    // equivalent to _dispatch_lock_owner(lock_value) == tid
    //異或操作:相同為0万皿,不同為1,如果相同,則為0相寇,0 &任何數(shù)都為0
    //即判斷 當(dāng)前要等待的任務(wù) 和 正在執(zhí)行的任務(wù)是否一樣慰于,通俗的解釋就是 執(zhí)行和等待的是否在同一隊(duì)列
    return ((lock_value ^ tid) & DLOCK_OWNER_MASK) == 0;
}

如果當(dāng)前等待的和正在執(zhí)行的是同一個(gè)隊(duì)列,即判斷線程ID是否相乘唤衫,如果相等婆赠,則會(huì)造成死鎖

同步函數(shù) + 并發(fā)隊(duì)列 順序執(zhí)行的原因

在_dispatch_sync_invoke_and_complete -> _dispatch_sync_function_invoke_inline源碼中,主要有三個(gè)步驟:

  • 將任務(wù)壓入隊(duì)列: _dispatch_thread_frame_push
  • 執(zhí)行任務(wù)的block回調(diào): _dispatch_client_callout
  • 將任務(wù)出隊(duì):_dispatch_thread_frame_pop

從實(shí)現(xiàn)中可以看出佳励,是先將任務(wù)push隊(duì)列中休里,然后執(zhí)行block回調(diào),在將任務(wù)pop赃承,所以任務(wù)是順序執(zhí)行的妙黍。

綜上所述,同步函數(shù)的底層分析如下

  • 同步函數(shù)的底層實(shí)現(xiàn)實(shí)際是同步柵欄函數(shù)

  • 同步函數(shù)中如果當(dāng)前正在執(zhí)行的隊(duì)列和等待的是同一個(gè)隊(duì)列瞧剖,形成相互等待的局面拭嫁,則會(huì)造成死鎖

步驟如下:


三 、總結(jié)

分析了這一階段的源碼之后抓于,我覺(jué)得了解下基本流程就行了,最后都來(lái)到底層函數(shù)封裝的調(diào)用做粤。接下來(lái)我們分析GCD的另外一部分,GCD底層原理下捉撮,單例怕品,柵欄函數(shù)、信號(hào)量等等巾遭。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肉康,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子灼舍,更是在濱河造成了極大的恐慌吼和,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骑素,死亡現(xiàn)場(chǎng)離奇詭異炫乓,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)砂豌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門厢岂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)光督,“玉大人阳距,你說(shuō)我怎么就攤上這事〗峤瑁” “怎么了筐摘?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我咖熟,道長(zhǎng)圃酵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任馍管,我火速辦了婚禮郭赐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘确沸。我一直安慰自己捌锭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布罗捎。 她就那樣靜靜地躺著观谦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪桨菜。 梳的紋絲不亂的頭發(fā)上豁状,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音倒得,去河邊找鬼泻红。 笑死,一個(gè)胖子當(dāng)著我的面吹牛屎暇,可吹牛的內(nèi)容都是我干的承桥。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼根悼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼凶异!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起挤巡,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤剩彬,失蹤者是張志新(化名)和其女友劉穎财饥,沒(méi)想到半個(gè)月后瞒津,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溉愁,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡册烈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年纳像,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了骗绕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搅轿。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡助泽,死狀恐怖琴昆,靈堂內(nèi)的尸體忽然破棺而出氓鄙,到底是詐尸還是另有隱情,我是刑警寧澤业舍,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布抖拦,位于F島的核電站升酣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏态罪。R本人自食惡果不足惜噩茄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望复颈。 院中可真熱鬧绩聘,春花似錦、人聲如沸耗啦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)芹彬。三九已至蓄髓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間舒帮,已是汗流浹背会喝。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留玩郊,地道東北人肢执。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像译红,于是被迫代替她去往敵國(guó)和親预茄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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