写在前面,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_s
、dispatch_ 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
,传递参数:queue
和void *
指针。
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
类型最终展开的结构体类型如下所示,有非常多的属性。
- 基类的属性:
isa
、ref_cnt
、xref_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_s
与dispatch_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继承关系图
下面的结构图中只展开了常见的
写在后面,接近半个月对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);
原子操作
#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;