前言
之前已经尝试对GCD的各个API进行了简单的实践总结,并记录为博客,为深入研究,决定硬着头皮读一读GCD的源码-libdispatch-1008.220.2。
源码很难,嵌套很深,本文只是针对GCD常见API的底层实现作简单总结笔记,记录自己的一些理解。
前期了解
结构体
GCD的类都是struct定义的。但并不像runtime一样,直接使用:来继承定义。而是将所有的父类的数据成员,都平铺重复的写在一个个的struct中,这样做的好处应该是为了提高效率。
- 基类dispatch_object_t的定义:
如下,是一个联合,可以表示其中的任意类型,同OC中的基类指针。
1 | typedef union { |
- dispatch_continuation_s
我们向queue提交的任务,无论block还是function形式,最终都会被封装为dispatch_continuation_s。
1 | struct dispatch_continuation_s { |
- dispatch_object_s
dispatch_object_s结构体是整个GCD的基类,地位十分重要,
1 | struct dispatch_object_s { |
- dispatch_queue_s
dispatch_queue_s 和 dispatch_object_s 差别在于 dispatch_queue_s 多了DISPATCH_QUEUE_HEADER 和 dq_label[DISPATCH_QUEUE_MIN_LABEL_SIZE],我们从中也可以看出,我们队列起名要少于64个字符
1 | #define DISPATCH_QUEUE_MIN_LABEL_SIZE 64 |
一些宏定义
- 对变量的定义一般遵循以下格式:
1 | #define DISPATCH_DECL(name) typedef struct name##_s *name##_t |
typedef struct dispatch_queue_s *dispatch_queue_t;
1 |
|
int pthread_key_create(pthread_key_t key, void (destr_function) (void *))
1 |
|
int pthread_setspecific(pthread_key_t key, const void pointer)
void pthread_getspecific(pthread_key_t key)
1 |
|
pthread_key_t dispatch_queue_key;
pthread_key_t dispatch_sema4_key;
pthread_key_t dispatch_cache_key;
pthread_key_t dispatch_io_key;
pthread_key_t dispatch_apply_key;
pthread_key_t dispatch_bcounter_key;
1 |
|
#define fastpath(x) ((typeof(x))__builtin_expect((long)(x), ~0l))
#define slowpath(x) ((typeof(x))__builtin_expect((long)(x), 0l))
1 |
|
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
{
return _dispatch_lane_create_with_target(label, attr,
DISPATCH_TARGET_QUEUE_DEFAULT, true);
}
1 |
|
_dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
dispatch_queue_t tq, bool legacy){}
1 |
|
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
1 |
|
_dispatch_queue_attr_to_info(dispatch_queue_attr_t dqa)
{
//1、如果dqa为空,返回空的结构体。
dispatch_queue_attr_info_t dqai = { };
if (!dqa) return dqai;
if (dqa < _dispatch_queue_attrs ||
dqa >= &_dispatch_queue_attrs[DISPATCH_QUEUE_ATTR_COUNT]) {
DISPATCH_CLIENT_CRASH(dqa->do_vtable, "Invalid queue attribute");
}
// 2、根据结构体位域的设置进行区分
size_t idx = (size_t)(dqa - _dispatch_queue_attrs);
dqai.dqai_inactive = (idx % DISPATCH_QUEUE_ATTR_INACTIVE_COUNT);
idx /= DISPATCH_QUEUE_ATTR_INACTIVE_COUNT;
.
.
.
return dqai;
1 |
|
//根据核心方法1返回的结构体属性进行判断。
if (dqai.dqai_concurrent) {
// 通过dqai.dqai_concurrent 来区分并发和串行
// DISPATCH_VTABLE 这个宏在底层会生成如下类
// OS_dispatch_queue_concurrent_class
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
vtable = DISPATCH_VTABLE(queue_serial);
}
1 |
|
DISPATCH_CLASS_SYMBOL(name) OS_dispatch_##name##_class
1 |
|
//开辟内存 - 生成响应的对象 queue
//根据核心方法2中的vtable。
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s));
// 构造方法
_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);
//target类型
dq->do_targetq = tq;
1 |
|
dispatch_queue_t queueSer = dispatch_queue_create(“com.doungser.cn”, NULL);
dispatch_queue_t queueCon = dispatch_queue_create(“com.doungcon.cn”, DISPATCH_QUEUE_CONCURRENT);
1 |
|
(lldb) po queueSer
<OS_dispatch_queue_serial: com.doungser.cn[0x600002e17580] = { xref = 1, ref = 1, sref = 1, target = com.apple.root.default-qos.overcommit[0x1088a7f00], width = 0x1, state = 0x001ffe2000000000, in-flight = 0}>
(lldb) po queueCon
<OS_dispatch_queue_concurrent: com.doungcon.cn[0x600002e17500] = { xref = 1, ref = 1, sref = 1, target = com.apple.root.default-qos[0x1088a7e80], width = 0xffe, state = 0x0000041000000000, in-flight = 0}>
1 |
|
#define DISPATCH_QUEUE_WIDTH_FULL 0x1000ull
#define DISPATCH_QUEUE_WIDTH_MAX (DISPATCH_QUEUE_WIDTH_FULL - 2)
1 |
|
#define dispatch_get_main_queue() (&_dispatch_main_q)
1 |
struct dispatch_queue_s _dispatch_main_q = {
.do_vtable = &_dispatch_queue_vtable,
.do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT,
.do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT,
.do_suspend_cnt = DISPATCH_OBJECT_SUSPEND_LOCK,
.do_targetq = &_dispatch_root_queues[DISPATCH_ROOT_QUEUE_COUNT / 2],
.dq_label = "com.apple.main-thread",
.dq_running = 1,
.dq_width = 1,
.dq_serialnum = 1,
};
1 |
|
dispatch_get_global_queue(long priority, unsigned long flags)
{
dispatch_assert(countof(_dispatch_root_queues) ==
DISPATCH_ROOT_QUEUE_COUNT);
if (flags & ~(unsigned long)DISPATCH_QUEUE_OVERCOMMIT) {
return DISPATCH_BAD_INPUT;
}
dispatch_qos_t qos = _dispatch_qos_from_queue_priority(priority);
#if !HAVE_PTHREAD_WORKQUEUE_QOS
if (qos == QOS_CLASS_MAINTENANCE) {
qos = DISPATCH_QOS_BACKGROUND;
} else if (qos == QOS_CLASS_USER_INTERACTIVE) {
qos = DISPATCH_QOS_USER_INITIATED;
}
#endif
if (qos == DISPATCH_QOS_UNSPECIFIED) {
return DISPATCH_BAD_INPUT;
}
//直接去root_queue中获取。
return _dispatch_get_root_queue(qos, flags & DISPATCH_QUEUE_OVERCOMMIT);
}
1 |
|
static inline dispatch_qos_t
_dispatch_qos_from_queue_priority(long priority)
{
switch (priority) {
case DISPATCH_QUEUE_PRIORITY_BACKGROUND: return DISPATCH_QOS_BACKGROUND;
case DISPATCH_QUEUE_PRIORITY_NON_INTERACTIVE: return DISPATCH_QOS_UTILITY;
case DISPATCH_QUEUE_PRIORITY_LOW: return DISPATCH_QOS_UTILITY;
case DISPATCH_QUEUE_PRIORITY_DEFAULT: return DISPATCH_QOS_DEFAULT;
case DISPATCH_QUEUE_PRIORITY_HIGH: return DISPATCH_QOS_USER_INITIATED;
default: return _dispatch_qos_from_qos_class((qos_class_t)priority);
}
}
`