11--多線程04--GCD類(lèi)型定義

寫(xiě)在前面谦炬,GCD確實(shí)是非常抽象的一個(gè)庫(kù),很容易讓人產(chǎn)生放棄的情緒辛藻,但“誰(shuí)無(wú)暴風(fēng)勁雨時(shí)捌省,守得云開(kāi)見(jiàn)月明”苫纤。首先需要找到GCD的源碼:libdispatch-1271.120.2 ,拿到源碼之后就可以開(kāi)心的解剖了纲缓。然而卷拘,GCD源碼中的類(lèi)型實(shí)在是太抽象了,不像objc源碼中的規(guī)規(guī)整整的結(jié)構(gòu)體祝高,而是宏定義栗弟,非常龐大的宏定義。另外工闺,GCD中的方法調(diào)用嵌套也是非常深乍赫,十幾層那是家常便飯÷襟。《庖丁解爬壮В》中指出,除了要有鋒利的刀叠殷,還需要知道這頭牛內(nèi)部結(jié)構(gòu)是啥樣的改鲫,哪里有硬骨頭,哪里好下刀。所以第一步應(yīng)該是先將這些類(lèi)型結(jié)構(gòu)展開(kāi)成我們熟悉的結(jié)構(gòu)體樣式钩杰。

一纫塌、結(jié)構(gòu)體的繼承

1.1 _os_object_s——os系統(tǒng)類(lèi)

系統(tǒng)的對(duì)象類(lèi),GCD中不直接使用這種類(lèi)型讲弄,類(lèi)型定義為:

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

將_OS_OBJECT_HEADER展開(kāi)來(lái)看:

#define _OS_OBJECT_HEADER(isa, ref_cnt, xref_cnt) \
        isa; /* must be pointer-sized and use __ptrauth_objc_isa_pointer */ \
        int volatile ref_cnt; \
        int volatile xref_cnt
  • volatile 提示編譯器變量隨時(shí)有可能改變,總與編譯器優(yōu)化有關(guān)依痊;
  • 返回一個(gè)_os_object_s對(duì)象
  • 常用作GCD類(lèi)中的構(gòu)造方法

1.2 dispatch_object_t——isa描述類(lèi)

聯(lián)合體類(lèi)型避除,繼承于_os_object_s結(jié)構(gòu)體中,一般第一個(gè)屬性表示繼承的父類(lèi))胸嘁,本身沒(méi)有成員變量瓶摆,包含GCD中所有類(lèi)型的指針,可以被理解為GCD中的isa的類(lèi)型描述性宏,定義為:

typedef union {
    struct _os_object_s *_os_obj;
    struct dispatch_object_s *_do;
    struct dispatch_queue_s *_dq;
    struct dispatch_queue_attr_s *_dqa;
    struct dispatch_group_s *_dg;
    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;
    struct dispatch_data_s *_ddata;
    struct dispatch_io_s *_dchannel;
} dispatch_object_t DISPATCH_TRANSPARENT_UNION;
  • GCD中的基類(lèi)群井,用來(lái)表示GCD中的各種類(lèi)型

1.3 dispatch_object_s——GCD基類(lèi)

繼承于_os_object_s,結(jié)構(gòu)體的繼承:通常情況下毫胜,將結(jié)構(gòu)體的第一個(gè)屬性稱(chēng)為父類(lèi)书斜,只是邏輯上的繼承,沒(méi)有OC中明顯的繼承符號(hào)酵使。在后面的分析中荐吉,可以發(fā)現(xiàn)這個(gè)類(lèi)結(jié)構(gòu)是GCD中絕大部分類(lèi)的基類(lèi)。
在GCD中口渔,通過(guò)宏的方式样屠,將父類(lèi)的屬性在子類(lèi)中重寫(xiě),定義如下:

struct dispatch_object_s {
    _DISPATCH_OBJECT_HEADER(object);
};

dispatch_object_s類(lèi)型中只有一個(gè)宏定義:_DISPATCH_OBJECT_HEADER(object);缺脉,完全看不出內(nèi)部結(jié)構(gòu)是啥樣子的痪欲,為了能探索下去,只能將宏展開(kāi):_DISPATCH_OBJECT_HEADER

#define _DISPATCH_OBJECT_HEADER(x) \
    struct _os_object_s _as_os_obj[0]; \
    OS_OBJECT_STRUCT_HEADER(dispatch_##x); \
    struct dispatch_##x##_s *volatile do_next; \
    struct dispatch_queue_s *do_targetq; \
    void *do_ctxt; \
    union { \
        dispatch_function_t DISPATCH_FUNCTION_POINTER do_finalizer; \
        void *do_introspection_ctxt; \
    }

展開(kāi)之后攻礼,發(fā)現(xiàn)內(nèi)部還有一個(gè)宏:OS_OBJECT_STRUCT_HEADER(dispatch_##x)业踢,所以只能繼續(xù)展開(kāi):

#define OS_OBJECT_STRUCT_HEADER(x) \
    _OS_OBJECT_HEADER(\
    const struct x##_vtable_s *__ptrauth_objc_isa_pointer do_vtable, \
    do_ref_cnt, \
    do_xref_cnt)
#endif

展開(kāi)的結(jié)構(gòu)中仍然還包裹著一層宏:_OS_OBJECT_HEADER,但回顧_os_object_s結(jié)構(gòu)時(shí)秘蛔,可以發(fā)現(xiàn)陨亡,宏定義已經(jīng)到頭了,可以認(rèn)為dispatch_object_s是繼承_os_object_s對(duì)象的:

#define _OS_OBJECT_HEADER(isa, ref_cnt, xref_cnt) \
        isa; /* must be pointer-sized and use __ptrauth_objc_isa_pointer */ \
        int volatile ref_cnt; \
        int volatile xref_cnt

我們逐層將宏定義展開(kāi)深员,并將參數(shù)帶進(jìn)來(lái)進(jìn)行替換负蠕,最終的數(shù)據(jù)結(jié)構(gòu)是:

struct _os_object_s _as_os_obj[0];
const struct dispatch_object_vtable_s *do_vtable;// 重寫(xiě)isa指針do_ref_cnt;//重寫(xiě)內(nèi)部引用計(jì)數(shù)
do_xref_cnt;//重寫(xiě)外部引用計(jì)數(shù)struct dispatch_queue_s *do_targetq;//指定的隊(duì)列void *do_ctxt;//union {
     dispatch_function_t do_finalizer;     void *do_introspection_ctxt;}

這種格式的結(jié)構(gòu)體比最開(kāi)始的宏定義的結(jié)構(gòu)體要清晰多了。在GCD的分析中倦畅,首先應(yīng)該將宏定義逐層展開(kāi)遮糖,還原結(jié)構(gòu)體本身的模樣。

二叠赐、宏定義結(jié)構(gòu)

這里猜測(cè)下蘋(píng)果為什么要用和么復(fù)雜的宏定義欲账?可能是因?yàn)閿?shù)據(jù)結(jié)構(gòu)有非常多的屬性屡江,而對(duì)于這些數(shù)據(jù)結(jié)構(gòu)中又有大量的相同屬性,少量的差異屬性赛不,使用宏定義可以減少大量的類(lèi)型定義的代碼惩嘉,使類(lèi)型的封裝性更高。
通過(guò)分析更多的GCD數(shù)據(jù)結(jié)構(gòu)踢故,可以看出大部分宏定義內(nèi)部最終都會(huì)指向那幾個(gè)基礎(chǔ)的宏定義文黎,本節(jié)將對(duì)宏定義進(jìn)行展開(kāi)說(shuō)明。

2.1 _OS_OBJECT_HEADER—— _os_object_s

在GCD中殿较,所有的宏定義解析耸峭,最終都會(huì)指向這個(gè)宏定義,對(duì)應(yīng)的類(lèi)型是_os_object_s淋纲。如果把它理解為基類(lèi)劳闹,描述了一個(gè)GCD對(duì)象中應(yīng)該有的基礎(chǔ)屬性:

  • isa:等同于objc對(duì)象中的isa指針;
  • ref_cnt:引用計(jì)數(shù)洽瞬,用作GCD內(nèi)部本涕;
  • xref_cnt:引用計(jì)數(shù),用作GCD外部片任;
_OS_OBJECT_HEADER(isa, ref_cnt, xref_cnt)
    isa;
    int volatile ref_cnt;
    int volatile xref_cnt;

OS_OBJECT_STRUCT_HEADER宏是對(duì)上面宏的一個(gè)包裝偏友,多了一個(gè)參數(shù)x,通過(guò)注釋可以看出GCD對(duì)象中isa的最終類(lèi)型會(huì)被轉(zhuǎn)換成:const struct x_vtable_s *对供,這個(gè)x就是從外面?zhèn)鬟^(guò)來(lái)的類(lèi)型位他,宏定義的替換發(fā)生在預(yù)編譯階段,所以代碼只有編譯起來(lái)之后才能看到GCD的類(lèi)型产场。

OS_OBJECT_STRUCT_HEADER(x)
    isa; // const struct x_vtable_s *
    int volatile ref_cnt;
    int volatile xref_cnt;

2.2 _DISPATCH_OBJECT_HEADER—— dispatch_object_s

從這個(gè)宏的名字定義來(lái)看鹅髓,表示的是GCD中的對(duì)象定義。將這個(gè)宏定義展開(kāi)之后的結(jié)構(gòu)如下京景,其中isa的注釋耐人尋味:const struct dispatch_x_vtable_s *窿冯,前面拼接了一個(gè)dispatch_的前綴,明確的表示的是GCD中的類(lèi)确徙。

_DISPATCH_OBJECT_HEADER(x)
    struct _os_object_s _as_os_obj[0];
    isa; // const struct dispatch_x_vtable_s *
    int volatile ref_cnt;
    int volatile xref_cnt;
    struct dispatch_x_s *volatile do_next;
    struct dispatch_queue_s *do_targetq;
    void *do_ctxt;
    union {
        dispatch_function_t DISPATCH_FUNCTION_POINTER do_finalizer;
        void *do_introspection_ctxt;
    }

DISPATCH_OBJECT_HEADER是對(duì)上面宏的包裝醒串,多了一個(gè)struct dispatch_x_s _as_do[0];屬性。

DISPATCH_OBJECT_HEADER(x)
    struct dispatch_x_s _as_do[0];
    // _DISPATCH_OBJECT_HEADER(x)
    struct _os_object_s _as_os_obj[0];
    isa; // const struct dispatch_x_vtable_s *
    int volatile ref_cnt;
    int volatile xref_cnt;
    struct dispatch_x_s *volatile do_next;
    struct dispatch_queue_s *do_targetq;
    void *do_ctxt;
    union {
        dispatch_function_t DISPATCH_FUNCTION_POINTER do_finalizer;
        void *do_introspection_ctxt;
    }

可以通過(guò)一個(gè)實(shí)例對(duì)象類(lèi)型來(lái)展開(kāi)宏看看鄙皇。在dispatch_object_s結(jié)構(gòu)體中芜赌,傳遞的是object,這個(gè)參數(shù)解析出來(lái)的類(lèi)型就是:dispatch_ object_vtable_s伴逸、dispatch_ object_s缠沈。

struct dispatch_object_s {
    _DISPATCH_OBJECT_HEADER(object);
};

2.3 _DISPATCH_QUEUE_CLASS_HEADER——dispatch_queue_s

先來(lái)看看dispatch_queue_s的類(lèi)型定義,內(nèi)部宏:DISPATCH_QUEUE_CLASS_HEADER,傳遞參數(shù):queuevoid *指針。

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

_DISPATCH_QUEUE_CLASS_HEADER宏表示隊(duì)列類(lèi)的基礎(chǔ)屬性、父類(lèi)屬性

_DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__)
    // DISPATCH_OBJECT_HEADER(x)
    struct dispatch_x_s _as_do[0];
    struct _os_object_s _as_os_obj[0];
    isa; // const struct dispatch_x_vtable_s *
    int volatile ref_cnt;
    int volatile xref_cnt;
    struct dispatch_x_s *volatile do_next;
    struct dispatch_queue_s *do_targetq;
    void *do_ctxt;
    union {
        dispatch_function_t DISPATCH_FUNCTION_POINTER do_finalizer;
        void *do_introspection_ctxt;
    }
    __pointer_sized_field__;
    DISPATCH_UNION_LE(uint64_t volatile dq_state,
            dispatch_lock dq_state_lock,
            uint32_t dq_state_bits
    )

dispatch_queue_s類(lèi)型最終展開(kāi)的結(jié)構(gòu)體類(lèi)型如下所示彻犁,有非常多的屬性。

  • 基類(lèi)的屬性:isa亡问、ref_cntxref_cnt
  • 隊(duì)列的并發(fā)數(shù):dq_serialnum肛宋,可以控制串行還是并行
  • 隊(duì)列的標(biāo)簽:dq_label玛界,我們?cè)趧?chuàng)建隊(duì)列時(shí)填的
  • 隊(duì)列的優(yōu)先級(jí):dq_priority,可以通過(guò)API設(shè)定隊(duì)列優(yōu)先級(jí)
    -隊(duì)列的任務(wù)數(shù):dq_sref_cnt悼吱,同步、異步添加的任務(wù)
    其他的Union類(lèi)型一般都是針對(duì)某個(gè)屬性的描述良狈,本身并不具有真實(shí)值后添。分析到這里,隊(duì)列的數(shù)據(jù)結(jié)構(gòu)就非常明了了薪丁。結(jié)合到我們平時(shí)通過(guò)GCD的一些API的調(diào)用可以看出遇西,最終都是為了修改其中的某個(gè)屬性。
DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__)
    // _DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__)
    struct dispatch_x_s _as_do[0];
    struct _os_object_s _as_os_obj[0];
    isa; // const struct dispatch_x_vtable_s *
    int volatile ref_cnt;
    int volatile xref_cnt;
    struct dispatch_x_s *volatile do_next;
    struct dispatch_queue_s *do_targetq;
    void *do_ctxt;
    union {
        dispatch_function_t DISPATCH_FUNCTION_POINTER do_finalizer;
        void *do_introspection_ctxt;
    }
    __pointer_sized_field__;
    DISPATCH_UNION_LE(uint64_t volatile dq_state,
            dispatch_lock dq_state_lock,
            uint32_t dq_state_bits
    )

    /* LP64 global queue cacheline boundary */
    unsigned long dq_serialnum;
    const char *dq_label;
    DISPATCH_UNION_LE(uint32_t volatile dq_atomic_flags,
        const uint16_t dq_width,
        const uint16_t __dq_opaque2
    );
    dispatch_priority_t dq_priority;
    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

2.4 DISPATCH_SOURCE_CLASS_HEADER—— dispatch_source_s

先來(lái)看看dispatch_source_s結(jié)構(gòu)體的定義严嗜,同樣也只有一個(gè)宏定義:DISPATCH_SOURCE_CLASS_HEADER粱檀,接受參數(shù):source。同樣的配方漫玄,我們將這個(gè)宏定義展開(kāi)看看茄蚯。

struct dispatch_source_s {
    DISPATCH_SOURCE_CLASS_HEADER(source);
} DISPATCH_ATOMIC64_ALIGN;

DISPATCH_SOURCE_CLASS_HEADER的內(nèi)部依賴(lài)一個(gè)新的宏:DISPATCH_LANE_CLASS_HEADER,結(jié)構(gòu)如下睦优∩#可以看出來(lái),宏:DISPATCH_LANE_CLASS_HEADER內(nèi)部任然依賴(lài)宏:DISPATCH_QUEUE_CLASS_HEADER汗盘,這個(gè)宏就是上面的
dispatch_queue_s對(duì)象皱碘,由此可見(jiàn)dispatch_source_sdispatch_queue_s有非常大關(guān)聯(lián)。在上一篇博客11--多線程探索03--GCD應(yīng)用中介紹了dispatch_source_t作為定時(shí)器的使用案例隐孽。dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);創(chuàng)建方法第四個(gè)參數(shù)就接受一個(gè)隊(duì)列癌椿,由此可見(jiàn),這個(gè)隊(duì)列的使用就在這里菱阵。文章的最后還介紹的dispatch_source_t作為定時(shí)器的暫停和恢復(fù)踢俄,宏DISPATCH_LANE_CLASS_HEADER的最后一個(gè)屬性dq_side_suspend_cnt,從字面義上可以看出這個(gè)跟dispatch_source_t的暫停相關(guān)送粱。

DISPATCH_LANE_CLASS_HEADER(x)
    struct dispatch_queue_s _as_dq[0];
        // DISPATCH_QUEUE_CLASS_HEADER
    struct dispatch_x_s _as_do[0];
    struct _os_object_s _as_os_obj[0];
    isa; // const struct dispatch_x_vtable_s *
    int volatile ref_cnt;
    int volatile xref_cnt;
    struct dispatch_x_s *volatile do_next;
    struct dispatch_queue_s *do_targetq;
    void *do_ctxt;
    union {
        dispatch_function_t DISPATCH_FUNCTION_POINTER do_finalizer;
        void *do_introspection_ctxt;
    }
    __pointer_sized_field__;
    DISPATCH_UNION_LE(uint64_t volatile dq_state,
            dispatch_lock dq_state_lock,
            uint32_t dq_state_bits
    )

    /* LP64 global queue cacheline boundary */
    unsigned long dq_serialnum;
    const char *dq_label;
    DISPATCH_UNION_LE(uint32_t volatile dq_atomic_flags,
        const uint16_t dq_width,
        const uint16_t __dq_opaque2
    );
    dispatch_priority_t dq_priority;
    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
        // DISPATCH_QUEUE_CLASS_HEADER
    dispatch_unfair_lock_s dq_sidelock;
    struct dispatch_object_s *volatile dq_items_head;
    uint32_t dq_side_suspend_cnt

dispatch_source_s類(lèi)型最終展開(kāi)的結(jié)構(gòu)體類(lèi)型如下所示褪贵,相對(duì)于上面的類(lèi)型中多了兩個(gè)聯(lián)合體。同樣的,聯(lián)合體往往都會(huì)被看出是對(duì)某個(gè)字段的解釋脆丁。從注釋中也可以清晰的看出世舰,下面的的位域在鎖的作用下表示不同的含義,具體釋義可以在后面的分析中嘗試分析槽卫。

DISPATCH_SOURCE_CLASS_HEADER(x)
    struct dispatch_queue_s _as_dq[0];
    struct dispatch_source_s _as_do[0];
    struct _os_object_s _as_os_obj[0];
    isa; // const struct dispatch_source_vtable_s *
    int volatile ref_cnt;
    int volatile xref_cnt;
    struct dispatch_source_s *volatile do_next;
    struct dispatch_queue_s *do_targetq;
    void *do_ctxt;
    union {
        dispatch_function_t DISPATCH_FUNCTION_POINTER do_finalizer;
        void *do_introspection_ctxt;
    }
    __pointer_sized_field__;
    DISPATCH_UNION_LE(uint64_t volatile dq_state,
            dispatch_lock dq_state_lock,
            uint32_t dq_state_bits
    )

    /* LP64 global queue cacheline boundary */
    unsigned long dq_serialnum;
    const char *dq_label;
    DISPATCH_UNION_LE(uint32_t volatile dq_atomic_flags,
        const uint16_t dq_width,
        const uint16_t __dq_opaque2
    );
    dispatch_priority_t dq_priority;
    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
    dispatch_unfair_lock_s dq_sidelock;
    struct dispatch_object_s *volatile dq_items_head;
    uint32_t dq_side_suspend_cnt
    uint16_t
        /* set under the drain lock */
        ds_is_installed:1,
        ds_latched:1,
        dm_connect_handler_called:1,
        dm_cancel_handler_called:1,
        dm_is_xpc:1,
        dm_arm_no_senders:1,
        dm_made_sendrights:1,
        dm_strict_reply:1,
        __ds_flags_pad : 8;
    uint16_t __dq_flags_separation[0];
    uint16_t
        /* set under the send queue lock */
        dm_needs_mgr:1,
        dm_disconnected:1,
        __dm_flags_pad : 14

2.5 DISPATCH_OBJECT_HEADER——dispatch_semaphore_s

最后一種我們熟知的GCD類(lèi)型——信號(hào)量跟压,dispatch_semaphore_s。在11--多線程探索03--GCD應(yīng)用中也介紹了dispatch_semaphore_s的強(qiáng)大之處歼培,但它的結(jié)構(gòu)非常簡(jiǎn)單震蒋,至少比上面幾種類(lèi)型的結(jié)構(gòu)要簡(jiǎn)單得多。

struct dispatch_semaphore_s {
    DISPATCH_OBJECT_HEADER(semaphore);
    intptr_t volatile dsema_value;
    intptr_t dsema_orig;
    _dispatch_sema4_t dsema_sema;
};

直接繼承了dispatch_object_s對(duì)象躲庄,全部展開(kāi)如下所示:

  • dsema_value:當(dāng)前的信號(hào)量大小
  • dsema_orig:原始信號(hào)量大小
  • dsema_sema:用來(lái)和內(nèi)核通信的信號(hào)量數(shù)值
struct dispatch_semaphore_s {
        struct dispatch_ semaphore_s _as_do[0];
    // _DISPATCH_OBJECT_HEADER(x)
    struct _os_object_s _as_os_obj[0];
    isa; // const struct dispatch_ semaphore_vtable_s *
    int volatile ref_cnt;
    int volatile xref_cnt;
    struct dispatch_ semaphore_s *volatile do_next;
    struct dispatch_queue_s *do_targetq;
    void *do_ctxt;
    union {
        dispatch_function_t DISPATCH_FUNCTION_POINTER do_finalizer;
        void *do_introspection_ctxt;
    }
    intptr_t volatile dsema_value;
    intptr_t dsema_orig;
    _dispatch_sema4_t dsema_sema;
};

到這里查剖,我們對(duì)常見(jiàn)的幾種GCD類(lèi)型的數(shù)據(jù)結(jié)構(gòu)就有個(gè)非常清晰的了解了≡刖剑回到面向?qū)ο笞钤镜囊?guī)則——萬(wàn)物皆對(duì)象笋庄,所有的GCD類(lèi)型也都能視為對(duì)象,所以我們后面就從面向?qū)ο蟮乃季S來(lái)分析它們的變化倔监。

三直砂、GCD繼承關(guān)系圖

下面的結(jié)構(gòu)圖中只展開(kāi)了常見(jiàn)的


GCD常見(jiàn)類(lèi)關(guān)系圖
GCD常見(jiàn)類(lèi)關(guān)系圖

寫(xiě)在后面,接近半個(gè)月對(duì)libdispatch-1271.120.2分析的過(guò)程不那么順利浩习,異常復(fù)雜的嵌套静暂,類(lèi)型嵌套和調(diào)用嵌套都非常深,總會(huì)讓人迷失在嵌套的地獄中谱秽,往往看到后面就不知道是當(dāng)前類(lèi)型是啥了洽蛀,只有將所有的宏定義展開(kāi)才知道。所以這里找了一套早期的源碼弯院,OS X 10.9.5中的libdispatch-339.92.1辱士。

GCD數(shù)據(jù)結(jié)構(gòu)

Dispatch 中常用的宏定義及基礎(chǔ)知識(shí)

DISPATCH_DECL
#define DISPATCH_DECL(name) typedef struct name##_s *name##_t

GCD中的變量大多使用了這個(gè)宏,比如DISPATCH_DECL(dispatch_queue)展開(kāi)后是

typedef struct dispatch_queue_s *dispatch_queue_t听绳;

它的意思是定義一個(gè)dispatch_queue_t類(lèi)型的指針颂碘,指向了一個(gè)dispatch_queue_s類(lèi)型的結(jié)構(gòu)體。

fastpath vs slowpath
#define fastpath(x) ((typeof(x))__builtin_expect((long)(x), ~0l))
#define slowpath(x) ((typeof(x))__builtin_expect((long)(x), 0l))

__builtin_expect 是編譯器優(yōu)化匯編代碼的椅挣,fastpath(x) 依然返回 x头岔,只是告訴編譯器 x 的值一般不為 0,從而編譯器可以進(jìn)行優(yōu)化鼠证。同理峡竣,slowpath(x) 表示 x 的值很可能為 0,希望編譯器進(jìn)行優(yōu)化量九。

TSD:Thread Specific Data

Thread Specific Data(TSD)是指線程私有數(shù)據(jù)适掰。在多線程中颂碧,會(huì)用全局變量來(lái)實(shí)現(xiàn)多個(gè)函數(shù)間的數(shù)據(jù)共享,局部變量來(lái)實(shí)現(xiàn)內(nèi)部的單獨(dú)訪問(wèn)类浪。TSD則是能夠在同一個(gè)線程的不同函數(shù)中被訪問(wèn)载城,在不同線程時(shí),相同的鍵值獲取的數(shù)據(jù)隨線程不同而不同费就。可以通過(guò)pthread的相關(guān)api來(lái)實(shí)現(xiàn)TSD:

//創(chuàng)建key
int pthread_key_create(pthread_key_t *, void (* _Nullable)(void *));
//get方法
void* _Nullable pthread_getspecific(pthread_key_t);
//set方法
int pthread_setspecific(pthread_key_t , const void * _Nullable);
原子操作

c++原子操作庫(kù)

#define dispatch_atomic_xchg(p, n)  __sync_lock_test_and_set((p), (n))
#define dispatch_atomic_cmpxchg(p, o, n)    __sync_bool_compare_and_swap((p), (o), (n))
#define dispatch_atomic_inc(p)              __sync_add_and_fetch((p), 1)
#define dispatch_atomic_dec(p)              __sync_sub_and_fetch((p), 1)
#define dispatch_atomic_add(p, v)       __sync_add_and_fetch((p), (v))
#define dispatch_atomic_sub(p, v)       __sync_sub_and_fetch((p), (v))
#define dispatch_atomic_or(p, v)        __sync_fetch_and_or((p), (v))
#define dispatch_atomic_and(p, v)       __sync_fetch_and_and((p), (v))
  • _sync_lock_test_and_set((p), (n)) 將p設(shè)為value并返回p操作之前的值诉瓦。
  • __sync_bool_compare_and_swap((p), (o), (n)) 這兩個(gè)函數(shù)提供原子的比較和交換:如果p == o,就將n寫(xiě)入p(p代表地址,o代表oldValue力细,n代表newValue)
  • __sync_add_and_fetch((p), 1) 先自加1睬澡,再返回
  • __sync_sub_and_fetch((p), 1) 先自減1,再返回
  • __sync_add_and_fetch((p), (v)) 先自加v眠蚂,再返回
  • __sync_sub_and_fetch((p), (v)) 先自減v煞聪,再返回
  • __sync_fetch_and_or((p), (v)) 先返回,再進(jìn)行或運(yùn)算
  • __sync_fetch_and_and((p), (v)) 先返回逝慧,再進(jìn)行與運(yùn)算

Dispatch 關(guān)鍵數(shù)據(jù)結(jié)構(gòu)

源碼中數(shù)據(jù)結(jié)構(gòu)的命名一般是以_s和_t結(jié)尾米绕,其中_t是_s的指針類(lèi)型,_s是結(jié)構(gòu)體馋艺。比如dispatch_queue_t和dispatch_queue_s。

dispatch_object_s

dispatch_object_s 是GCD最基礎(chǔ)的結(jié)構(gòu)體迈套,相當(dāng)于基類(lèi)捐祠,類(lèi)似OC中的id類(lèi)型。定義如下:

struct dispatch_object_s {
    DISPATCH_STRUCT_HEADER(object);
};
//os object頭部宏定義
#define _OS_OBJECT_HEADER(isa, ref_cnt, xref_cnt) \
        isa; /* must be pointer-sized */ \  //isa
        int volatile ref_cnt; \             //引用計(jì)數(shù)
        int volatile xref_cnt               //外部引用計(jì)數(shù)桑李,兩者都為0釋放
//dispatch 結(jié)構(gòu)體頭部  
#define DISPATCH_STRUCT_HEADER(x) \
    _OS_OBJECT_HEADER( \
    const struct dispatch_##x##_vtable_s *do_vtable, \  //vtable 結(jié)構(gòu)體
    do_ref_cnt, \
    do_xref_cnt); \
    struct dispatch_##x##_s *volatile do_next; \        //下一個(gè)do 鏈表next
    struct dispatch_queue_s *do_targetq; \              //目標(biāo)隊(duì)列
    void *do_ctxt; \                                    //上下文
    void *do_finalizer; \                               //銷(xiāo)毀時(shí)調(diào)用函數(shù)
    unsigned int do_suspend_cnt;                        //suspend計(jì)數(shù)踱蛀, 用作暫停標(biāo)志
dispatch_object_t

dispatch_object_t是個(gè)union的聯(lián)合體,可以用dispatch_object_t代表這個(gè)聯(lián)合體里的所有數(shù)據(jù)結(jié)構(gòu)贵白。

union與結(jié)構(gòu)體有本質(zhì)的不同率拒,結(jié)構(gòu)體中各成員有各自的內(nèi)存空間,聯(lián)合體中的各成員共享一段內(nèi)存空間禁荒,一個(gè)聯(lián)合變量的長(zhǎng)度等于各成員最長(zhǎng)的長(zhǎng)度猬膨。用于節(jié)省內(nèi)存。

typedef union {
    struct _os_object_s *_os_obj;
    struct dispatch_object_s *_do;
    struct dispatch_continuation_s *_dc;
    struct dispatch_queue_s *_dq;
    struct dispatch_queue_attr_s *_dqa;
    struct dispatch_group_s *_dg;
    struct dispatch_source_s *_ds;
    struct dispatch_mach_s *_dm;
    struct dispatch_mach_msg_s *_dmsg;
    struct dispatch_timer_aggregate_s *_dta;
    struct dispatch_source_attr_s *_dsa;
    struct dispatch_semaphore_s *_dsema;
    struct dispatch_data_s *_ddata;
    struct dispatch_io_s *_dchannel;
    struct dispatch_operation_s *_doperation;
    struct dispatch_disk_s *_ddisk;
} dispatch_object_t __attribute__((__transparent_union__));
dispatch_xxx_vtable

DISPATCH_VTABLE_HEADER(x) vtable結(jié)構(gòu)體定義呛伴,包含了這個(gè)dispatch_object_s的操作函數(shù)

#define DISPATCH_VTABLE_HEADER(x) \
    unsigned long do_type; \                           //dispatch_object_s類(lèi)型 
    const char *do_kind; \                             //do 的說(shuō)明
    size_t (*do_debug)(struct dispatch_##x##_s *, char *, size_t); \ //debug方法
    void (*do_invoke)(struct dispatch_##x##_s *); \ //任務(wù)出隊(duì)時(shí)會(huì)觸發(fā)invoke函數(shù)
    unsigned long (*do_probe)(struct dispatch_##x##_s *); \ //用戶(hù)隊(duì)列創(chuàng)建的這個(gè)方法是空的勃痴,但rootqueue內(nèi)的這個(gè)有一個(gè) `_dispatch_queue_wakeup_global`函數(shù)。一般是喚醒隊(duì)列的方法
    void (*do_dispose)(struct dispatch_##x##_s *); //銷(xiāo)毀隊(duì)列的方法,內(nèi)部通常調(diào)用do_finalizer 函數(shù)热康。
    
    //dx_xxx 開(kāi)頭的宏定義沛申,本質(zhì)是調(diào)用vtable中定義的函數(shù)
#define dx_type(x) (x)->do_vtable->do_type
#define dx_metatype(x) ((x)->do_vtable->do_type & _DISPATCH_META_TYPE_MASK)
#define dx_kind(x) (x)->do_vtable->do_kind
#define dx_debug(x, y, z) (x)->do_vtable->do_debug((x), (y), (z))
#define dx_dispose(x) (x)->do_vtable->do_dispose(x)
#define dx_invoke(x) (x)->do_vtable->do_invoke(x)
#define dx_probe(x) (x)->do_vtable->do_probe(x)
dispatch_continuation_s

dispatch_continuation_s 結(jié)構(gòu)體主要封裝block和function,被傳入的block會(huì)變成這個(gè)結(jié)構(gòu)體對(duì)象傳入隊(duì)列。定義如下

#define DISPATCH_CONTINUATION_HEADER(x) \
    _OS_OBJECT_HEADER( \
    const void *do_vtable, \ 
    do_ref_cnt, \
    do_xref_cnt); \                                //os_object_header
    struct dispatch_##x##_s *volatile do_next; \   //下一個(gè)任務(wù) 鏈表next
    dispatch_function_t dc_func; \                 //  如 _dispatch_call_block_and_release 方法姐军,結(jié)構(gòu)體實(shí)際執(zhí)行的方法
    void *dc_ctxt; \                               // 調(diào)用dispatch_async 傳入的block 即待執(zhí)行的內(nèi)容,會(huì)作為參數(shù)傳入dc_func
    void *dc_data; \                               //相關(guān)數(shù)據(jù)
    void *dc_other;                                //其他
    
    struct dispatch_continuation_s {
    DISPATCH_CONTINUATION_HEADER(continuation);
};
dispatch_queue_s

dispatch_queue_s是隊(duì)列的結(jié)構(gòu)體铁材,是我們接觸最多的結(jié)構(gòu)體尖淘。

struct dispatch_queue_s {
    DISPATCH_STRUCT_HEADER(queue);
    DISPATCH_QUEUE_HEADER;
    DISPATCH_QUEUE_CACHELINE_PADDING; // for static queues only
};

#define DISPATCH_QUEUE_HEADER \
    uint32_t volatile dq_running; \                       //隊(duì)列運(yùn)行的任務(wù)數(shù)量
    struct dispatch_object_s *volatile dq_items_head; \ //頭節(jié)點(diǎn)
    /* LP64 global queue cacheline boundary */ \
    struct dispatch_object_s *volatile dq_items_tail; \ //尾節(jié)點(diǎn)
    dispatch_queue_t dq_specific_q; \                   //specifix隊(duì)列
    uint32_t dq_width; \                                //隊(duì)列并發(fā)數(shù)
    unsigned int dq_is_thread_bound:1; \               //是否線程綁定
    unsigned long dq_serialnum; \                      //隊(duì)列序號(hào)
    const char *dq_label; \                            //隊(duì)列名
    DISPATCH_INTROSPECTION_QUEUE_LIST;
最后編輯于
?著作權(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)離奇詭異,居然都是意外死亡葬毫,警方通過(guò)查閱死者的電腦和手機(jī)镇辉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)贴捡,“玉大人忽肛,你說(shuō)我怎么就攤上這事±谜” “怎么了屹逛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)汛骂。 經(jīng)常有香客問(wèn)我罕模,道長(zhǎng),這世上最難降的妖魔是什么帘瞭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任淑掌,我火速辦了婚禮,結(jié)果婚禮上蝶念,老公的妹妹穿的比我還像新娘抛腕。我一直安慰自己,他們只是感情好媒殉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布担敌。 她就那樣靜靜地躺著,像睡著了一般廷蓉。 火紅的嫁衣襯著肌膚如雪全封。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,554評(píng)論 1 305
  • 那天桃犬,我揣著相機(jī)與錄音售貌,去河邊找鬼。 笑死疫萤,一個(gè)胖子當(dāng)著我的面吹牛颂跨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扯饶,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼恒削,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼池颈!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起钓丰,我...
    開(kāi)封第一講書(shū)人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤躯砰,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后携丁,有當(dāng)?shù)厝嗽跇?shù)林里發(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
  • 文/蒙蒙 一匕得、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧巾表,春花似錦、人聲如沸略吨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)翠忠。三九已至鞠苟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間秽之,已是汗流浹背当娱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(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)容