美文网首页
11--多线程04--GCD类型定义

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

作者: 修_远 | 来源:发表于2021-07-16 22:38 被阅读0次

    写在前面,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;
    

    相关文章

      网友评论

          本文标题:11--多线程04--GCD类型定义

          本文链接:https://www.haomeiwen.com/subject/mvexpltx.html