11--多线程04--GCD类型定义

写在前面,GCD确实是非常抽象的一个库,很容易让人产生放弃的情绪,但“谁无暴风劲雨时,守得云开见月明”。首先需要找到GCD的源码:libdispatch-1271.120.2 ,拿到源码之后就可以开心的解剖了。然而,GCD源码中的类型实在是太抽象了,不像objc源码中的规规整整的结构体,而是宏定义,非常庞大的宏定义。另外,GCD中的方法调用嵌套也是非常深,十几层那是家常便饭。《庖丁解牛》中指出,除了要有锋利的刀,还需要知道这头牛内部结构是啥样的,哪里有硬骨头,哪里好下刀。所以第一步应该是先将这些类型结构展开成我们熟悉的结构体样式。

一、结构体的继承

1.1 _os_object_s——os系统类

系统的对象类,GCD中不直接使用这种类型,类型定义为:

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展开来看:

#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 提示编译器变量随时有可能改变,总与编译器优化有关;
  • 返回一个_os_object_s对象
  • 常用作GCD类中的构造方法

1.2 dispatch_object_t——isa描述类

联合体类型,继承于_os_object_s结构体中,一般第一个属性表示继承的父类),本身没有成员变量,包含GCD中所有类型的指针,可以被理解为GCD中的isa的类型描述,定义为:

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中的基类,用来表示GCD中的各种类型

1.3 dispatch_object_s——GCD基类

继承于_os_object_s,结构体的继承:通常情况下,将结构体的第一个属性称为父类,只是逻辑上的继承,没有OC中明显的继承符号。在后面的分析中,可以发现这个类结构是GCD中绝大部分类的基类。
在GCD中,通过宏的方式,将父类的属性在子类中重写,定义如下:

struct dispatch_object_s {
    _DISPATCH_OBJECT_HEADER(object);
};

dispatch_object_s类型中只有一个宏定义:_DISPATCH_OBJECT_HEADER(object);,完全看不出内部结构是啥样子的,为了能探索下去,只能将宏展开:_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; \
    }

展开之后,发现内部还有一个宏:OS_OBJECT_STRUCT_HEADER(dispatch_##x),所以只能继续展开:

#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

展开的结构中仍然还包裹着一层宏:_OS_OBJECT_HEADER,但回顾_os_object_s结构时,可以发现,宏定义已经到头了,可以认为dispatch_object_s是继承_os_object_s对象的:

#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

我们逐层将宏定义展开,并将参数带进来进行替换,最终的数据结构是:

struct _os_object_s _as_os_obj[0];
const struct dispatch_object_vtable_s *do_vtable;// 重写isa指针do_ref_cnt;//重写内部引用计数
do_xref_cnt;//重写外部引用计数struct dispatch_queue_s *do_targetq;//指定的队列void *do_ctxt;//union {
     dispatch_function_t do_finalizer;     void *do_introspection_ctxt;}

这种格式的结构体比最开始的宏定义的结构体要清晰多了。在GCD的分析中,首先应该将宏定义逐层展开,还原结构体本身的模样。

二、宏定义结构

这里猜测下苹果为什么要用和么复杂的宏定义?可能是因为数据结构有非常多的属性,而对于这些数据结构中又有大量的相同属性,少量的差异属性,使用宏定义可以减少大量的类型定义的代码,使类型的封装性更高。
通过分析更多的GCD数据结构,可以看出大部分宏定义内部最终都会指向那几个基础的宏定义,本节将对宏定义进行展开说明。

2.1 _OS_OBJECT_HEADER—— _os_object_s

在GCD中,所有的宏定义解析,最终都会指向这个宏定义,对应的类型是_os_object_s。如果把它理解为基类,描述了一个GCD对象中应该有的基础属性:

  • isa:等同于objc对象中的isa指针;
  • ref_cnt:引用计数,用作GCD内部;
  • xref_cnt:引用计数,用作GCD外部;
_OS_OBJECT_HEADER(isa, ref_cnt, xref_cnt)
    isa;
    int volatile ref_cnt;
    int volatile xref_cnt;

OS_OBJECT_STRUCT_HEADER宏是对上面宏的一个包装,多了一个参数x,通过注释可以看出GCD对象中isa的最终类型会被转换成:const struct x_vtable_s *,这个x就是从外面传过来的类型,宏定义的替换发生在预编译阶段,所以代码只有编译起来之后才能看到GCD的类型。

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

从这个宏的名字定义来看,表示的是GCD中的对象定义。将这个宏定义展开之后的结构如下,其中isa的注释耐人寻味:const struct dispatch_x_vtable_s *,前面拼接了一个dispatch_的前缀,明确的表示的是GCD中的类。

_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是对上面宏的包装,多了一个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;
    }

可以通过一个实例对象类型来展开宏看看。在dispatch_object_s结构体中,传递的是object,这个参数解析出来的类型就是:dispatch_ object_vtable_sdispatch_ object_s

struct dispatch_object_s {
    _DISPATCH_OBJECT_HEADER(object);
};

2.3 _DISPATCH_QUEUE_CLASS_HEADER——dispatch_queue_s

先来看看dispatch_queue_s的类型定义,内部宏:DISPATCH_QUEUE_CLASS_HEADER,传递参数:queuevoid *指针。

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

_DISPATCH_QUEUE_CLASS_HEADER宏表示队列类的基础属性、父类属性

_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类型最终展开的结构体类型如下所示,有非常多的属性。

  • 基类的属性:isaref_cntxref_cnt
  • 队列的并发数:dq_serialnum,可以控制串行还是并行
  • 队列的标签:dq_label,我们在创建队列时填的
  • 队列的优先级:dq_priority,可以通过API设定队列优先级
    -队列的任务数:dq_sref_cnt,同步、异步添加的任务
    其他的Union类型一般都是针对某个属性的描述,本身并不具有真实值。分析到这里,队列的数据结构就非常明了了。结合到我们平时通过GCD的一些API的调用可以看出,最终都是为了修改其中的某个属性。
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

先来看看dispatch_source_s结构体的定义,同样也只有一个宏定义:DISPATCH_SOURCE_CLASS_HEADER,接受参数:source。同样的配方,我们将这个宏定义展开看看。

struct dispatch_source_s {
    DISPATCH_SOURCE_CLASS_HEADER(source);
} DISPATCH_ATOMIC64_ALIGN;

DISPATCH_SOURCE_CLASS_HEADER的内部依赖一个新的宏:DISPATCH_LANE_CLASS_HEADER,结构如下。可以看出来,宏:DISPATCH_LANE_CLASS_HEADER内部任然依赖宏:DISPATCH_QUEUE_CLASS_HEADER,这个宏就是上面的
dispatch_queue_s对象,由此可见dispatch_source_sdispatch_queue_s有非常大关联。在上一篇博客11--多线程探索03--GCD应用中介绍了dispatch_source_t作为定时器的使用案例。dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);创建方法第四个参数就接受一个队列,由此可见,这个队列的使用就在这里。文章的最后还介绍的dispatch_source_t作为定时器的暂停和恢复,宏DISPATCH_LANE_CLASS_HEADER的最后一个属性dq_side_suspend_cnt,从字面义上可以看出这个跟dispatch_source_t的暂停相关。

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类型最终展开的结构体类型如下所示,相对于上面的类型中多了两个联合体。同样的,联合体往往都会被看出是对某个字段的解释。从注释中也可以清晰的看出,下面的的位域在锁的作用下表示不同的含义,具体释义可以在后面的分析中尝试分析。

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类型——信号量,dispatch_semaphore_s。在11--多线程探索03--GCD应用中也介绍了dispatch_semaphore_s的强大之处,但它的结构非常简单,至少比上面几种类型的结构要简单得多。

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对象,全部展开如下所示:

  • dsema_value:当前的信号量大小
  • dsema_orig:原始信号量大小
  • dsema_sema:用来和内核通信的信号量数值
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;
};

到这里,我们对常见的几种GCD类型的数据结构就有个非常清晰的了解了。回到面向对象最原本的规则——万物皆对象,所有的GCD类型也都能视为对象,所以我们后面就从面向对象的思维来分析它们的变化。

三、GCD继承关系图

下面的结构图中只展开了常见的


GCD常见类关系图
GCD常见类关系图

写在后面,接近半个月对libdispatch-1271.120.2分析的过程不那么顺利,异常复杂的嵌套,类型嵌套和调用嵌套都非常深,总会让人迷失在嵌套的地狱中,往往看到后面就不知道是当前类型是啥了,只有将所有的宏定义展开才知道。所以这里找了一套早期的源码,OS X 10.9.5中的libdispatch-339.92.1

GCD数据结构

Dispatch 中常用的宏定义及基础知识

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

GCD中的变量大多使用了这个宏,比如DISPATCH_DECL(dispatch_queue)展开后是

typedef struct dispatch_queue_s *dispatch_queue_t;

它的意思是定义一个dispatch_queue_t类型的指针,指向了一个dispatch_queue_s类型的结构体。

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 是编译器优化汇编代码的,fastpath(x) 依然返回 x,只是告诉编译器 x 的值一般不为 0,从而编译器可以进行优化。同理,slowpath(x) 表示 x 的值很可能为 0,希望编译器进行优化。

TSD:Thread Specific Data

Thread Specific Data(TSD)是指线程私有数据。在多线程中,会用全局变量来实现多个函数间的数据共享,局部变量来实现内部的单独访问。TSD则是能够在同一个线程的不同函数中被访问,在不同线程时,相同的键值获取的数据随线程不同而不同。可以通过pthread的相关api来实现TSD:

//创建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++原子操作库

#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设为value并返回p操作之前的值。
  • __sync_bool_compare_and_swap((p), (o), (n)) 这两个函数提供原子的比较和交换:如果p == o,就将n写入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)) 先返回,再进行或运算
  • __sync_fetch_and_and((p), (v)) 先返回,再进行与运算

Dispatch 关键数据结构

源码中数据结构的命名一般是以_s和_t结尾,其中_t是_s的指针类型,_s是结构体。比如dispatch_queue_t和dispatch_queue_s。

dispatch_object_s

dispatch_object_s 是GCD最基础的结构体,相当于基类,类似OC中的id类型。定义如下:

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; \             //引用计数
        int volatile xref_cnt               //外部引用计数,两者都为0释放
//dispatch 结构体头部  
#define DISPATCH_STRUCT_HEADER(x) \
    _OS_OBJECT_HEADER( \
    const struct dispatch_##x##_vtable_s *do_vtable, \  //vtable 结构体
    do_ref_cnt, \
    do_xref_cnt); \
    struct dispatch_##x##_s *volatile do_next; \        //下一个do 链表next
    struct dispatch_queue_s *do_targetq; \              //目标队列
    void *do_ctxt; \                                    //上下文
    void *do_finalizer; \                               //销毁时调用函数
    unsigned int do_suspend_cnt;                        //suspend计数, 用作暂停标志
dispatch_object_t

dispatch_object_t是个union的联合体,可以用dispatch_object_t代表这个联合体里的所有数据结构。

union与结构体有本质的不同,结构体中各成员有各自的内存空间,联合体中的各成员共享一段内存空间,一个联合变量的长度等于各成员最长的长度。用于节省内存。

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结构体定义,包含了这个dispatch_object_s的操作函数

#define DISPATCH_VTABLE_HEADER(x) \
    unsigned long do_type; \                           //dispatch_object_s类型 
    const char *do_kind; \                             //do 的说明
    size_t (*do_debug)(struct dispatch_##x##_s *, char *, size_t); \ //debug方法
    void (*do_invoke)(struct dispatch_##x##_s *); \ //任务出队时会触发invoke函数
    unsigned long (*do_probe)(struct dispatch_##x##_s *); \ //用户队列创建的这个方法是空的,但rootqueue内的这个有一个 `_dispatch_queue_wakeup_global`函数。一般是唤醒队列的方法
    void (*do_dispose)(struct dispatch_##x##_s *); //销毁队列的方法,内部通常调用do_finalizer 函数。
    
    //dx_xxx 开头的宏定义,本质是调用vtable中定义的函数
#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 结构体主要封装block和function,被传入的block会变成这个结构体对象传入队列。定义如下

#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; \   //下一个任务 链表next
    dispatch_function_t dc_func; \                 //  如 _dispatch_call_block_and_release 方法,结构体实际执行的方法
    void *dc_ctxt; \                               // 调用dispatch_async 传入的block 即待执行的内容,会作为参数传入dc_func
    void *dc_data; \                               //相关数据
    void *dc_other;                                //其他
    
    struct dispatch_continuation_s {
    DISPATCH_CONTINUATION_HEADER(continuation);
};
dispatch_queue_s

dispatch_queue_s是队列的结构体,是我们接触最多的结构体。

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; \                       //队列运行的任务数量
    struct dispatch_object_s *volatile dq_items_head; \ //头节点
    /* LP64 global queue cacheline boundary */ \
    struct dispatch_object_s *volatile dq_items_tail; \ //尾节点
    dispatch_queue_t dq_specific_q; \                   //specifix队列
    uint32_t dq_width; \                                //队列并发数
    unsigned int dq_is_thread_bound:1; \               //是否线程绑定
    unsigned long dq_serialnum; \                      //队列序号
    const char *dq_label; \                            //队列名
    DISPATCH_INTROSPECTION_QUEUE_LIST;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容