一、概述 Grand Central Dispatch(GCD)是 iOS 中一个强大的多线程编程框架,GCD 提供了一种高效、低级别的方式来管理并发任务。
GCD 是使用队列来调度任务的执行的,GCD 队列主要有这几种:
队列(Queue)
串行队列:任务按顺序执行,一个任务完成后才开始下一个任务。
并发队列:允许多个任务同时执行,任务的开始顺序是确定的,但完成顺序不一定。
主队列(Main Queue)
一个特殊的串行队列,用于在主线程上执行任务,通常用于更新 UI。
所有提交到主队列的任务,无论使用 dispatch_sync 还是 dispatch_async,都将在主线程执行。
全局并发队列(Global Concurrent Queue)
GCD 任务是指需要执行的代码块,有同步或异步执行两种方式:
同步执行(dispatch_sync) :阻塞当前线程,直到任务完成。
异步执行(dispatch_async) :立即返回,不阻塞当前线程,任务在后台执行。
其中,创建队列是通过 GCD 的 dispatch_queue_create
进行创建的:
1 2 3 4 5 dispatch_queue_t serialQueue = dispatch_queue_create("com.lixkit.serialQueue" , DISPATCH_QUEUE_SERIAL); dispatch_queue_t concurrentQueue = dispatch_queue_create("com.lixkit.concurrentQueue" , DISPATCH_QUEUE_CONCURRENT);
接下来,通过 libdispatch 源码,看 dispatch_queue_create
实现原理。
二、DISPATCH_QUEUE_SERIAL & DISPATCH_QUEUE_CONCURRENT 前面已经提到,创建队列是通过 dispatch_queue_create
进行创建的:
1 2 3 4 5 dispatch_queue_t serialQueue = dispatch_queue_create("com.lixkit.serialQueue" , DISPATCH_QUEUE_SERIAL); dispatch_queue_t concurrentQueue = dispatch_queue_create("com.lixkit.concurrentQueue" , DISPATCH_QUEUE_CONCURRENT);
创建串行队列和并发队列,用到了这两个宏:
DISPATCH_QUEUE_SERIAL
DISPATCH_QUEUE_CONCURRENT
1、DISPATCH_QUEUE_SERIAL DISPATCH_QUEUE_SERIAL
用于创建串行队列,这是个宏,其本质是 NULL
:
1 #define DISPATCH_QUEUE_SERIAL NULL
2、DISPATCH_QUEUE_CONCURRENT DISPATCH_QUEUE_CONCURRENT
也是一个宏,且其定义中使用了一系列的宏定义:
1 2 3 4 5 6 7 8 9 #define DISPATCH_QUEUE_CONCURRENT \ DISPATCH_GLOBAL_OBJECT(dispatch_queue_attr_t, \ _dispatch_queue_attr_concurrent) #define DISPATCH_GLOBAL_OBJECT(type, object) ((OS_OBJECT_BRIDGE type)&(object)) struct dispatch_queue_attr_s _dispatch_queue_attr_concurrent ;#define OS_OBJECT_BRIDGE __bridge
将其完全展开后定义如下:
1 2 #define DISPATCH_QUEUE_CONCURRENT \ ((__bridge dispatch_queue_attr_t)&(_dispatch_queue_attr_concurrent))
即 DISPATCH_QUEUE_CONCURRENT
是 dispatch_queue_attr_t
类型的指针,该指针是由全局变量 _dispatch_queue_attr_concurrent
的地址强制转换成的。
_dispatch_queue_attr_concurrent
是什么呢? 上面提到,DISPATCH_QUEUE_CONCURRENT
是由全局变量 _dispatch_queue_attr_concurrent
转换成的,那么 _dispatch_queue_attr_concurrent
具体是什么呢?
可以看下 init.c
中下述源码:
1 2 3 4 5 6 7 const struct dispatch_queue_attr_s _dispatch_queue_attrs [] = { [0 ... DISPATCH_QUEUE_ATTR_COUNT - 1 ] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_attr), }, };
在注释中明确提到, DISPATCH_QUEUE_CONCURRENT
和 _dispatch_queue_attr_concurrent
都是 _dispatch_queue_attrs
数组第 0
个元素的别名。即:DISPATCH_QUEUE_CONCURRENT
本质是 _dispatch_queue_attrs
数组第 0
个元素。
在上述 _dispatch_queue_attrs
数组的定义中,DISPATCH_QUEUE_ATTR_COUNT
宏定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #define DISPATCH_QOS_USER_INTERACTIVE ((dispatch_qos_t)6) #define DISPATCH_QOS_MAX DISPATCH_QOS_USER_INTERACTIVE #define QOS_MIN_RELATIVE_PRIORITY (-15) #define DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT 3 #define DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT 3 #define DISPATCH_QUEUE_ATTR_QOS_COUNT (DISPATCH_QOS_MAX + 1) #define DISPATCH_QUEUE_ATTR_PRIO_COUNT (1 - QOS_MIN_RELATIVE_PRIORITY) #define DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT 2 #define DISPATCH_QUEUE_ATTR_INACTIVE_COUNT 2 #define DISPATCH_QUEUE_ATTR_COUNT ( \ DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT * \ DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT * \ DISPATCH_QUEUE_ATTR_QOS_COUNT * \ DISPATCH_QUEUE_ATTR_PRIO_COUNT * \ DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT * \ DISPATCH_QUEUE_ATTR_INACTIVE_COUNT )
可以看到 DISPATCH_QUEUE_ATTR_COUNT
是一系列宏参与乘法计算,其最终计算结果是 4032
。
DISPATCH_GLOBAL_OBJECT_HEADER
宏定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #define DISPATCH_GLOBAL_OBJECT_HEADER(name) \ .do_vtable = DISPATCH_VTABLE(name), \ .do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, \ .do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT #define DISPATCH_VTABLE(name) DISPATCH_OBJC_CLASS(name) #define DISPATCH_OBJC_CLASS(name) (&DISPATCH_CLASS_SYMBOL(name)) #define DISPATCH_CLASS_SYMBOL(name) _dispatch_##name##_vtable #define DISPATCH_OBJECT_GLOBAL_REFCNT _OS_OBJECT_GLOBAL_REFCNT #define _OS_OBJECT_GLOBAL_REFCNT INT_MAX
将 DISPATCH_GLOBAL_OBJECT_HEADER(queue_attr)
完全展开后如下:
1 2 3 .do_vtable = (&_dispatch_queue_attr_vtable), .do_ref_cnt = INT_MAX, .do_xref_cnt = INT_MAX
综上, _dispatch_queue_attrs
实际定义为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const struct dispatch_queue_attr_s _dispatch_queue_attrs [] = { [0 ... 4032 - 1 ] = { .do_vtable = (&_dispatch_queue_attr_vtable), .do_ref_cnt = INT_MAX, .do_xref_cnt = INT_MAX }, };
尽管 _dispatch_queue_attrs
中 4032
个元素的初始值相同,但实际使用过程中会根据不同的条件或配置修改特定元素的属性,以支持不同的队列行为或策略。通过 _dispatch_queue_attrs
数组索引直接访问属性组合,而不是在运行时计算或生成新的组合,提升了访问的速度和效率。而 DISPATCH_QUEUE_CONCURRENT
则是 _dispatch_queue_attrs
数组的第 0
个元素。
三、dispatch_queue_create dispatch_queue_create
函数源码如下:
1 2 3 4 5 6 dispatch_queue_t 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、参数 label & attr (1)label 参数 char *
类型的参数,用于为队列指定一个标识符,通常是一个描述性的字符串。label 参数对队列的功能和行为没有影响,主要用于调试和日志记录,帮助开发者识别和跟踪不同的队列。经常使用反向域名格式(如 "com.lixkit.serialQueue"
),以确保标签的唯一性和可读性。
(2)attr 参数 attr
参数,直接从方法定义上看是 dispatch_queue_attr_t
类型,实际上,其源码实现如下:
1 2 DISPATCH_DECL(dispatch_queue_attr); #define DISPATCH_DECL(name) typedef struct name##_s *name##_t
这意味着 dispatch_queue_attr_t
是 struct dispatch_queue_attr_s
的指针类型,dispatch_queue_attr_s
的定义涉及到一系列宏定义和其他结构体的嵌套,将其完全展开后源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 struct dispatch_queue_attr_s { struct _os_object_s _as_os_obj [0]; const struct dispatch_queue_attr_vtable_s *__ptrauth_objc_isa_pointer do_vtable ; int do_ref_cnt; int do_xref_cnt; };
2、返回值 dispatch_queue_t dispatch_queue_create
的返回值是 dispatch_queue_t
,dispatch_queue_t
是一个指向 dispatch_queue_s
结构体的指针:
1 typedef struct dispatch_queue_s *dispatch_queue_t ;
dispatch_queue_s
是一个复杂的结构体,包含了许多宏定义和其他结构体的嵌套。完全展开后的 dispatch_queue_s
源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 struct dispatch_queue_s { struct dispatch_object_s _as_do [0]; struct _os_object_s _as_os_obj [0]; const struct dispatch_queue_vtable_s *__ptrauth_objc_isa_pointer do_vtable ; int volatile do_ref_cnt; int volatile do_xref_cnt; struct dispatch_queue_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; }; void *__dq_opaque1; union { uint64_t volatile dq_state; dispatch_lock dq_state_lock; uint32_t dq_state_bits; }; unsigned long dq_serialnum; const char *dq_label; union { uint32_t volatile dq_atomic_flags; struct { 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; } __attribute__((aligned(8 )));
在 dispatch_queue_s
中,有多个匿名联合体,例如对于其中的:
1 2 3 4 5 6 7 8 union { uint32_t volatile dq_atomic_flags; struct { const uint16_t dq_width; const uint16_t __dq_opaque2; }; };
匿名联合体中还有个匿名结构体,该数据结构总结如下:
联合体(union
)
联合体中的所有成员共享同一段内存。
dq_atomic_flags
和下面的匿名结构体共享同一段内存,对 dq_atomic_flags
赋值实际上就是对下面的结构体赋值。
dq_atomic_flags
是 32
位的无符号整数类型,其占用了 32
位的内存区域。
匿名结构体
上述源码中结构体是匿名的,包含两个 uint16_t
类型的成员:dq_width
和 __dq_opaque2
,即各自分别占用 16
位内存。
由于结构体的成员在内存中的排序是按照它们声明的顺序依次排列的,所以 dq_width
和 __dq_opaque2
分别占用 dq_atomic_flags
的低 16
位和高 16
位。
3、_dispatch_lane_create_with_target 再回头看下 dispatch_queue_create
函数的定义:
1 2 3 4 5 6 dispatch_queue_t dispatch_queue_create (const char *label, dispatch_queue_attr_t attr) { return _dispatch_lane_create_with_target(label, attr, DISPATCH_TARGET_QUEUE_DEFAULT, true ); }
可以看到,dispatch_queue_create
函数内部主要是调用了 _dispatch_lane_create_with_target
函数。
其中第三个参数 DISPATCH_TARGET_QUEUE_DEFAULT
本质是个 NULL
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 #define DISPATCH_TARGET_QUEUE_DEFAULT NULL ```c `_dispatch_lane_create_with_target` 实现源码如下: ```c static dispatch_queue_t _dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa, dispatch_queue_t tq, bool legacy) { dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa); dispatch_qos_t qos = dqai.dqai_qos; #if !HAVE_PTHREAD_WORKQUEUE_QOS if (qos == DISPATCH_QOS_USER_INTERACTIVE) { dqai.dqai_qos = qos = DISPATCH_QOS_USER_INITIATED; } if (qos == DISPATCH_QOS_MAINTENANCE) { dqai.dqai_qos = qos = DISPATCH_QOS_BACKGROUND; } #endif _dispatch_queue_attr_overcommit_t overcommit = dqai.dqai_overcommit; if (overcommit != _dispatch_queue_attr_overcommit_unspecified && tq) { if (tq->do_targetq) { DISPATCH_CLIENT_CRASH(tq, "Cannot specify both overcommit and " "a non-global target queue" ); } } if (tq && dx_type(tq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE) { if (overcommit == _dispatch_queue_attr_overcommit_unspecified) { if (tq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) { overcommit = _dispatch_queue_attr_overcommit_enabled; } else { overcommit = _dispatch_queue_attr_overcommit_disabled; } } if (qos == DISPATCH_QOS_UNSPECIFIED) { qos = _dispatch_priority_qos(tq->dq_priority); } tq = NULL ; } else if (tq && _dispatch_queue_is_cooperative(tq)) { DISPATCH_CLIENT_CRASH(tq, "Cannot target object to cooperative root queue - not implemented" ); } else if (tq && !tq->do_targetq) { if (overcommit != _dispatch_queue_attr_overcommit_unspecified) { DISPATCH_CLIENT_CRASH(tq, "Cannot specify an overcommit attribute " "and use this kind of target queue" ); } } else { if (overcommit == _dispatch_queue_attr_overcommit_unspecified) { overcommit = dqai.dqai_concurrent ? _dispatch_queue_attr_overcommit_disabled : _dispatch_queue_attr_overcommit_enabled; } } if (!tq) { uintptr_t flags = (overcommit == _dispatch_queue_attr_overcommit_enabled) ? DISPATCH_QUEUE_OVERCOMMIT : 0 ; tq = _dispatch_get_root_queue( qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, flags)->_as_dq; if (unlikely(!tq)) { DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute" ); } } if (legacy) { if (dqai.dqai_inactive || dqai.dqai_autorelease_frequency) { legacy = false ; } } const void *vtable; dispatch_queue_flags_t dqf = legacy ? DQF_MUTABLE : 0 ; if (dqai.dqai_concurrent) { vtable = DISPATCH_VTABLE(queue_concurrent); } else { vtable = DISPATCH_VTABLE(queue_serial); } switch (dqai.dqai_autorelease_frequency) { case DISPATCH_AUTORELEASE_FREQUENCY_NEVER: dqf |= DQF_AUTORELEASE_NEVER; break ; case DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM: dqf |= DQF_AUTORELEASE_ALWAYS; break ; } if (label) { const char *tmp = _dispatch_strdup_if_mutable(label); if (tmp != label) { dqf |= DQF_LABEL_NEEDS_FREE; label = tmp; } } 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); if (overcommit == _dispatch_queue_attr_overcommit_enabled) { dq->dq_priority |= DISPATCH_PRIORITY_FLAG_OVERCOMMIT; } if (!dqai.dqai_inactive) { _dispatch_queue_priority_inherit_from_target(dq, tq); _dispatch_lane_inherit_wlh_from_target(dq, tq); } _dispatch_retain(tq); dq->do_targetq = tq; _dispatch_object_debug(dq, "%s" , __func__); return _dispatch_trace_queue_create(dq)._dq; }
上述逻辑比较多,可以将上面逻辑拆分成下面这部分:
生成 dqai
(dispatch_queue_attr_info_t
)
创建 tq
(dispatch_queue_t
)
初始化队列 dq
(dispatch_lane_t
)
dq
其他配置
接下来,基于源码分别看下上述各部分逻辑。
(1)生成 dqai dqai
是 dispatch_queue_attr_info_t
结构体类型,dqai
中包含了队列的服务质量(QoS)、相对优先级、超额提交属性、自动释放频率、并发性和非活动状态等信息。
dispatch_queue_attr_info_t
结构体定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 typedef struct dispatch_queue_attr_info_s { dispatch_qos_t dqai_qos : 8 ; int dqai_relpri : 8 ; uint16_t dqai_overcommit : 2 ; uint16_t dqai_autorelease_frequency : 2 ; uint16_t dqai_concurrent : 1 ; uint16_t dqai_inactive : 1 ; } dispatch_queue_attr_info_t ;
生成 dqai
是通过 _dispatch_queue_attr_to_info
函数实现的,_dispatch_queue_attr_to_info
函数实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 dispatch_queue_attr_info_t _dispatch_queue_attr_to_info(dispatch_queue_attr_t 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" ); } size_t idx = (size_t )(dqa - _dispatch_queue_attrs); dqai.dqai_inactive = (idx % DISPATCH_QUEUE_ATTR_INACTIVE_COUNT); idx /= DISPATCH_QUEUE_ATTR_INACTIVE_COUNT; dqai.dqai_concurrent = !(idx % DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT); idx /= DISPATCH_QUEUE_ATTR_CONCURRENCY_COUNT; dqai.dqai_relpri = -(int )(idx % DISPATCH_QUEUE_ATTR_PRIO_COUNT); idx /= DISPATCH_QUEUE_ATTR_PRIO_COUNT; dqai.dqai_qos = idx % DISPATCH_QUEUE_ATTR_QOS_COUNT; idx /= DISPATCH_QUEUE_ATTR_QOS_COUNT; dqai.dqai_autorelease_frequency = idx % DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT; idx /= DISPATCH_QUEUE_ATTR_AUTORELEASE_FREQUENCY_COUNT; dqai.dqai_overcommit = idx % DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT; idx /= DISPATCH_QUEUE_ATTR_OVERCOMMIT_COUNT; return dqai; }
前面已经提到,当创建串行队列时,attr
参数为 DISPATCH_QUEUE_SERIAL
,本质为 NULL
。此时 _dispatch_queue_attr_to_info
函数返回值为:
1 2 3 4 5 6 7 8 dispatch_queue_attr_info_t dqai = { .dqai_qos = 0 , .dqai_relpri = 0 , .dqai_overcommit = 0 , .dqai_autorelease_frequency = 0 , .dqai_concurrent = 0 , .dqai_inactive = 0 };
当创建并发队列时,attr
参数为 DISPATCH_QUEUE_CONCURRENT
,此时 _dispatch_queue_attr_to_info
函数返回值为:
1 2 3 4 5 6 7 8 dispatch_queue_attr_info_t dqai = { .dqai_qos = 0, .dqai_relpri = 0, .dqai_overcommit = 0, .dqai_autorelease_frequency = 0, .dqai_concurrent = 1, // 并发队列 .dqai_inactive = 0 };
所以,当创建串行、并发队列时,_dispatch_queue_attr_to_info
函数返回的结果仅 dqai_concurrent
值不同,分别是 0
和 1
。
(2)创建 tq 根据前述源码,在创建 tq 前需要先获取超额提交属性 overcommit
,dispatch_queue_create
函数在调用时 _dispatch_lane_create_with_target
,tq
参数传入的是 DISPATCH_TARGET_QUEUE_DEFAULT
,前面已经提到,DISPATCH_TARGET_QUEUE_DEFAULT
本质是个 NULL
,所以会走调用下面的 if 分支:
1 2 3 4 5 if (overcommit == _dispatch_queue_attr_overcommit_unspecified) { overcommit = dqai.dqai_concurrent ? _dispatch_queue_attr_overcommit_disabled : _dispatch_queue_attr_overcommit_enabled; }
所以,创建串行队列时,overcommi
t 为 _dispatch_queue_attr_overcommit_enabled
。创建并发队列时,overcommit
为 _dispatch_queue_attr_overcommit_enabled
。
从此处可以得到一个结论:串行队列是 overcommit
的,并发队列是非 overcommit
的。
接下来进入 tq
的创建逻辑:
1 2 3 4 5 6 7 8 9 10 11 if (!tq) { uintptr_t flags = (overcommit == _dispatch_queue_attr_overcommit_enabled) ? DISPATCH_QUEUE_OVERCOMMIT : 0 ; tq = _dispatch_get_root_queue( qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, flags)->_as_dq; if (unlikely(!tq)) { DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute" ); } }
其中,_dispatch_get_root_queue
实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 static inline dispatch_queue_global_t _dispatch_get_root_queue(dispatch_qos_t qos, uintptr_t flags) { if (unlikely(qos < DISPATCH_QOS_MIN || qos > DISPATCH_QOS_MAX)) { DISPATCH_CLIENT_CRASH(qos, "Corrupted priority" ); } unsigned int add_on = 0 ; if (flags & DISPATCH_QUEUE_OVERCOMMIT) { add_on = DISPATCH_ROOT_QUEUE_IDX_OFFSET_OVERCOMMIT; } else if (flags & DISPATCH_QUEUE_COOPERATIVE) { add_on = DISPATCH_ROOT_QUEUE_IDX_OFFSET_COOPERATIVE; } return &_dispatch_root_queues[3 * (qos - 1 ) + add_on]; }
这里先看下 _dispatch_root_queues
,_dispatch_root_queues
是一个 dispatch_queue_global_s
类型的数组,先看下 dispatch_queue_global_s
的定义,dispatch_queue_global_s
的定义涉及击到一系列宏,将其完全展开后如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 struct dispatch_queue_global_s { struct dispatch_queue_s _as_dq [0]; struct dispatch_object_s _as_do [0]; struct _os_object_s _as_os_obj [0]; const struct dispatch_lane_vtable_s *__ptrauth_objc_isa_pointer do_vtable ; int volatile do_ref_cnt; int volatile do_xref_cnt; struct dispatch_lane_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; }; struct dispatch_object_s *volatile dq_items_tail ; int volatile dgq_thread_pool_size; struct dispatch_object_s *volatile dq_items_head ; int volatile dgq_pending; union { uint64_t volatile dq_state; dispatch_lock dq_state_lock; uint32_t dq_state_bits; }; unsigned long dq_serialnum; const char *dq_label; union { uint32_t volatile dq_atomic_flags; struct { 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; } __attribute__((__aligned__(64 )));
可以看到,dispatch_queue_global_s
与前面提到的 dispatch_queue_s
结构几乎是一样的,最大的区别是 dispatch_queue_global_s
中多了个 struct dispatch_queue_s _as_dq[0];
的零长数组,意味着可以通过 _as_dq
将 dispatch_queue_global_s
转成 dispatch_queue_s
。
这种设计在 libdispatch 的源码中非常常见,通常用于类型转换或类型兼容性,这种设计的原理是:
内存布局和对齐
在 C 语言中,结构体的内存布局是由其成员的声明顺序决定的。编译器会按照声明的顺序为每个成员分配内存,并根据目标平台的对齐要求进行对齐。
零长度数组在内存中不占用空间,但它的存在可以影响后续成员的对齐和布局。
类型转换的目的
当一个结构体包含另一个结构体的零长度数组时,编译器会将该数组视作一个指向数组元素类型的指针。这意味着,在内存布局上,该结构体的起始位置与零长度数组的元素类型的起始位置一致。
通过这种方式,包含零长度数组的结构体可以与数组元素类型具有相同的内存起始布局,从而实现类型兼容。
类型兼容性的实现
例如,dispatch_queue_global_s
包含 struct dispatch_queue_s _as_dq[0]
,这意味着在内存布局上,dispatch_queue_global_s
的起始位置与 dispatch_queue_s
的起始位置一致。
这允许通过 _as_dq
指针将 dispatch_queue_global_s
视作 dispatch_queue_s
,因为它们在内存中的起始位置是相同的。
实现多态性
这种设计模式允许使用不同类型的结构体通过相同的接口进行操作,实现多态性和灵活性。
通过零长度数组或灵活数组成员,开发者可以在不增加内存开销的情况下,实现类型之间的灵活转换。
_dispatch_root_queues
的定义中也涉及到一系列宏定义,将 _dispatch_root_queues
内部宏定义完全展开后,实际内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 struct dispatch_queue_global_s _dispatch_root_queues [] = { [DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_MAINTENANCE, 0 ), .dq_label = "com.apple.root.maintenance-qos" , .dq_serialnum = 4 , }, [DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS_OVERCOMMIT] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS_OVERCOMMIT), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_MAINTENANCE, 0 ) | DISPATCH_PRIORITY_FLAG_OVERCOMMIT, .dq_label = "com.apple.root.maintenance-qos.overcommit" , .dq_serialnum = 5 , }, [DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS_COOPERATIVE] = { .do_vtable = DISPATCH_VTABLE(queue_concurrent), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_MAINTENANCE, 0 ) | DISPATCH_PRIORITY_FLAG_COOPERATIVE, .dq_label = "com.apple.root.maintenance-qos.cooperative" , .dq_serialnum = 6 , }, [DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_BACKGROUND, 0 ), .dq_label = "com.apple.root.background-qos" , .dq_serialnum = 7 , }, [DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS_OVERCOMMIT] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS_OVERCOMMIT), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_BACKGROUND, 0 ) | DISPATCH_PRIORITY_FLAG_OVERCOMMIT, .dq_label = "com.apple.root.background-qos.overcommit" , .dq_serialnum = 8 , }, [DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS_COOPERATIVE] = { .do_vtable = DISPATCH_VTABLE(queue_concurrent), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_BACKGROUND, 0 ) | DISPATCH_PRIORITY_FLAG_COOPERATIVE, .dq_label = "com.apple.root.background-qos.cooperative" , .dq_serialnum = 9 , }, [DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_UTILITY, 0 ), .dq_label = "com.apple.root.utility-qos" , .dq_serialnum = 10 , }, [DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS_OVERCOMMIT] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS_OVERCOMMIT), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_UTILITY, 0 ) | DISPATCH_PRIORITY_FLAG_OVERCOMMIT, .dq_label = "com.apple.root.utility-qos.overcommit" , .dq_serialnum = 11 , }, [DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS_COOPERATIVE] = { .do_vtable = DISPATCH_VTABLE(queue_concurrent), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_UTILITY, 0 ) | DISPATCH_PRIORITY_FLAG_COOPERATIVE, .dq_label = "com.apple.root.utility-qos.cooperative" , .dq_serialnum = 12 , }, [DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make_fallback(DISPATCH_QOS_DEFAULT), .dq_label = "com.apple.root.default-qos" , .dq_serialnum = 13 , }, [DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make_fallback(DISPATCH_QOS_DEFAULT) | DISPATCH_PRIORITY_FLAG_OVERCOMMIT, .dq_label = "com.apple.root.default-qos.overcommit" , .dq_serialnum = 14 , }, [DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_COOPERATIVE] = { .do_vtable = DISPATCH_VTABLE(queue_concurrent), .dq_priority = _dispatch_priority_make_fallback(DISPATCH_QOS_DEFAULT) | DISPATCH_PRIORITY_FLAG_COOPERATIVE, .dq_label = "com.apple.root.default-qos.cooperative" , .dq_serialnum = 15 , }, [DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_USER_INITIATED, 0 ), .dq_label = "com.apple.root.user-initiated-qos" , .dq_serialnum = 16 , }, [DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS_OVERCOMMIT] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS_OVERCOMMIT), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_USER_INITIATED, 0 ) | DISPATCH_PRIORITY_FLAG_OVERCOMMIT, .dq_label = "com.apple.root.user-initiated-qos.overcommit" , .dq_serialnum = 17 , }, [DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS_COOPERATIVE] = { .do_vtable = DISPATCH_VTABLE(queue_concurrent), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_USER_INITIATED, 0 ) | DISPATCH_PRIORITY_FLAG_COOPERATIVE, .dq_label = "com.apple.root.user-initiated-qos.cooperative" , .dq_serialnum = 18 , }, [DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_USER_INTERACTIVE, 0 ), .dq_label = "com.apple.root.user-interactive-qos" , .dq_serialnum = 19 , }, [DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS_OVERCOMMIT] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS_OVERCOMMIT), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_USER_INTERACTIVE, 0 ) | DISPATCH_PRIORITY_FLAG_OVERCOMMIT, .dq_label = "com.apple.root.user-interactive-qos.overcommit" , .dq_serialnum = 20 , }, [DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS_COOPERATIVE] = { .do_vtable = DISPATCH_VTABLE(queue_concurrent), .dq_priority = _dispatch_priority_make(DISPATCH_QOS_USER_INTERACTIVE, 0 ) | DISPATCH_PRIORITY_FLAG_COOPERATIVE, .dq_label = "com.apple.root.user-interactive-qos.cooperative" , .dq_serialnum = 21 , }, };
根据源码可知,_dispatch_root_queues
本质就是一个数组,数组的 index
是个枚举,源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 enum { DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS = 0 , DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS_COOPERATIVE, DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS, DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS_COOPERATIVE, DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS, DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS_COOPERATIVE, DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS, DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_COOPERATIVE, DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS, DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS_COOPERATIVE, DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS, DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS_OVERCOMMIT, DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS_COOPERATIVE, _DISPATCH_ROOT_QUEUE_IDX_COUNT, };
根据枚举定义也可以看出,数组的 index
是通过不同的调度策略进行拼接的,_dispatch_get_root_queue
中会根据不同的策略计算出对应的 index
从 _dispatch_root_queues
数组中取值。
再回到 _dispatch_get_root_queue
函数,看创建串行、并发队列时,传入的 index
,经过计算可以知道,创建串行队列时,index = 10
,创建并发队列时 index = 9
。
所以创建串行队列时,返回的是 _dispatch_root_queues
数组 index = 10
的元素(DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT
),即:
1 2 3 4 5 6 7 8 9 [DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make_fallback(DISPATCH_QOS_DEFAULT) | DISPATCH_PRIORITY_FLAG_OVERCOMMIT, .dq_label = "com.apple.root.default-qos.overcommit" , .dq_serialnum = 14 , },
创建并发队列时,返回的是 _dispatch_root_queues
数组 index = 9
的元素(DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS
),即:
1 2 3 4 5 6 7 8 9 [DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS] = { DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, .do_ctxt = _dispatch_root_queue_ctxt(DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS), .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), .dq_priority = _dispatch_priority_make_fallback(DISPATCH_QOS_DEFAULT), .dq_label = "com.apple.root.default-qos" , .dq_serialnum = 13 , },
这里创建完成的 tq
会在前述的 _dispatch_lane_create_with_target
后续逻辑中被设置成队列的 do_targetq
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 static dispatch_queue_t _dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa, dispatch_queue_t tq, bool legacy) { if (!tq) { uintptr_t flags = (overcommit == _dispatch_queue_attr_overcommit_enabled) ? DISPATCH_QUEUE_OVERCOMMIT : 0 ; tq = _dispatch_get_root_queue( qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, flags)->_as_dq; } dq->do_targetq = tq; return _dispatch_trace_queue_create(dq)._dq; }
所以对于自定义的队列,无论是串行队列还是并发队列,其 do_targetq
都是从根队列数组 _dispatch_root_queues
中取出的对应的根队列(root queue)。
(3)初始化队列 dq(dispatch_lane_t) _dispatch_lane_create_with_target
函数中,创建的 dq
是 dispatch_lane_t
类型,那 dispatch_lane_t
和前面提到的 dispatch_queue_s
类型是什么关系呢?
dispatch_lane_t
是一个指向 dispatch_lane_s
结构体的指针类型。dispatch_lane_s
是 dispatch_queue_s
的子类型,继承了队列的基本功能,并扩展了用于任务调度的字段:
1 2 3 4 5 6 7 8 9 struct dispatch_lane_s { struct dispatch_object_s *dq_items_head ; struct dispatch_object_s *dq_items_tail ; dispatch_unfair_lock_s dq_sidelock; };
从 _dispatch_lane_create_with_target
函数实现上来看,如果创建的串行队列还是并发队列,返回的都是 dispatch_lane_s
类型。
初始化队列 dq
可以分成两部分逻辑来看:
a、分配内存 分配内存主要是通过 _dispatch_object_alloc
函数实现的:
1 2 dispatch_lane_t dq = _dispatch_object_alloc(vtable, sizeof (struct dispatch_lane_s));
其中,vtable
参数值通过下述逻辑获取的:
1 2 3 4 5 6 7 if (dqai.dqai_concurrent) { vtable = DISPATCH_VTABLE(queue_concurrent); } else { vtable = DISPATCH_VTABLE(queue_serial); }
vtable
实际上是一个虚表(虚函数表),虚表主要用于支持多态性和动态方法调用,允许对象在运行时调用对应的函数实现。一个类中有虚函数(virtual
关键字声明的函数)时,编译器会自动为该类及其派生类自动生成虚表,虚表中的指针会指向派生类的实现。
可以简单理解为虚表中存储了函数具体实现的指针。对应的类或结构体,通过访问虚表中的函数指针可以调用到对应的函数实现。
由上述源码可以知道,当创建串行队列时,vtable
为 &_dispatch_queue_serial_vtable
,当创建并发队列时,vtabl
e 为 &_dispatch_queue_concurrent_vtable
。
接下来以 _dispatch_queue_concurrent_vtable
为例,看下源码实现。从 libdispatch 的源码中,找到了如下宏:
1 DISPATCH_SUBCLASS_DECL(queue_concurrent, queue , lane);
根据源码,将宏完全展开后如下:
1 2 3 4 5 6 7 8 9 @protocol OS_dispatch_queue_concurrent <OS_dispatch_queue> @end @interface OS_dispatch_queue_concurrent () <OS_dispatch_queue_concurrent> @end struct dispatch_queue_concurrent_s;extern const struct dispatch_lane_vtable_s _OS_dispatch_queue_concurrent_vtable ;extern const struct dispatch_lane_vtable_s _dispatch_queue_concurrent_vtable __asm__ ("__OS_dispatch_queue_concurrent_vtable ");
从上述源码可以看出,_OS_dispatch_queue_concurrent_vtable
是 OS_dispatch_queue_concurrent
类的虚表,之后又通过 __asm__
指令在汇编代码中将 _OS_dispatch_queue_concurrent_vtable
与 _dispatch_queue_concurrent_vtable
进行关联。
所以 _dispatch_queue_concurrent_vtable
对应的实现类是 OS_dispatch_queue_concurrent
,而 _dispatch_queue_concurrent_vtable
中则存储了 OS_dispatch_queue_concurrent
类相关函数的实现的指针。
这也是为什么将创建的并发队列打印出来之后,显示 OS_dispatch_queue_concurrent
的原因:
同样的,根据源码可以知道创建串行队列,对应的实现类是 OS_dispatch_queue_serial
。
从 libdispatch 的源码的下述源码,可以看到 _dispatch_queue_concurrent_vtable
中存储的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_concurrent, lane, .do_type = DISPATCH_QUEUE_CONCURRENT_TYPE, .do_dispose = _dispatch_lane_dispose, .do_debug = _dispatch_queue_debug, .do_invoke = _dispatch_lane_invoke, .dq_activate = _dispatch_lane_activate, .dq_wakeup = _dispatch_lane_wakeup, .dq_push = _dispatch_lane_concurrent_push, ); #define DISPATCH_VTABLE_SUBCLASS_INSTANCE(name, ctype, ...) \ OS_OBJECT_VTABLE_SUBCLASS_INSTANCE(dispatch_##name, dispatch_##ctype, \ _dispatch_xref_dispose, _dispatch_dispose, \ .do_kind = #name, __VA_ARGS__) #define OS_OBJECT_VTABLE_SUBCLASS_INSTANCE(name, ctype, xdispose, dispose, ...) \ const struct ctype##_vtable_s OS_OBJECT_CLASS_SYMBOL(name) = { \ ._os_obj_xref_dispose = xdispose, \ ._os_obj_dispose = dispose, \ ._os_obj_vtable = { __VA_ARGS__ }, \ } #define OS_OBJECT_CLASS_SYMBOL(name) _##name##_vtable
将宏完全展开后如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const struct dispatch_lane_vtable_s _dispatch_queue_concurrent_vtable = { ._os_obj_xref_dispose = _dispatch_xref_dispose, ._os_obj_dispose = _dispatch_dispose, ._os_obj_vtable = { .do_kind = "queue_concurrent" , .do_type = DISPATCH_QUEUE_CONCURRENT_TYPE, .do_dispose = _dispatch_lane_dispose, .do_debug = _dispatch_queue_debug, .do_invoke = _dispatch_lane_invoke, .dq_activate = _dispatch_lane_activate, .dq_wakeup = _dispatch_lane_wakeup, .dq_push = _dispatch_lane_concurrent_push, }, }
同样的,也可以看到 _dispatch_queue_serial_vtable
内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const struct dispatch_lane_vtable_s _dispatch_queue_serial_vtable = { ._os_obj_xref_dispose = _dispatch_xref_dispose, ._os_obj_dispose = _dispatch_dispose, ._os_obj_vtable = { .do_kind = "queue_serial" , .do_type = DISPATCH_QUEUE_SERIAL_TYPE, .do_dispose = _dispatch_lane_dispose, .do_debug = _dispatch_queue_debug, .do_invoke = _dispatch_lane_invoke, .dq_activate = _dispatch_lane_activate, .dq_wakeup = _dispatch_lane_wakeup, .dq_push = _dispatch_lane_push, }, };
其中存储的各个函数实现在 libdispatch 的源码中都可以找到,这里就不一一贴出来了。
再回头看下分配内存逻辑:
1 2 dispatch_lane_t dq = _dispatch_object_alloc(vtable, sizeof (struct dispatch_lane_s));
其中 _dispatch_object_alloc
函数实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 void *_dispatch_object_alloc(const void *vtable, size_t size) { return _os_object_alloc_realized(vtable, size); } inline _os_object_t _os_object_alloc_realized(const void *cls, size_t size) { _os_object_t obj; dispatch_assert(size >= sizeof (struct _os_object_s)); while (unlikely(!(obj = calloc (1u , size)))) { _dispatch_temporary_resource_shortage(); } obj->os_obj_isa = cls; return obj; }
上述主要逻辑如下:
创建 _os_object_t
类型的对象 obj
,并分配内存。
将 vtable
赋值给 obj->os_obj_isa
。
vtable
是虚表,存储了具体的函数实现的指针。
串行队列时,vtable
虚表对应实现类是 OS_dispatch_queue_serial
并发队列时,vtable
虚表对应实现类是 OS_dispatch_queue_concurrent
b、初始化 初始化是通过调用 _dispatch_queue_init
函数实现的:
1 2 3 _dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ? DISPATCH_QUEUE_WIDTH_MAX : 1 , DISPATCH_QUEUE_ROLE_INNER | (dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0 ));
调用 _dispatch_queue_init
传入了 4 个参数,根据源码可知,创建串行队列时,第 3 个参数(width
)传入的十进制值是 1;
创建并发队列时,第 3 个参数(width
)传入的十进制值是 DISPATCH_QUEUE_WIDTH_MAX,DISPATCH_QUEUE_WIDTH_MAX
是个宏:
1 2 #define DISPATCH_QUEUE_WIDTH_FULL 0x1000ull #define DISPATCH_QUEUE_WIDTH_MAX (DISPATCH_QUEUE_WIDTH_FULL - 2)
经过计算,DISPATCH_QUEUE_WIDTH_MAX
的十进制值是 4094
,所以创建串行队列时,第 3 个参数(width
)传入的十进制值是 4094
;
结合前面生成 dqai
那部分的源码,可以知道无论串行队列还是并发队列,dqai.dqai_inactive
值都是 0,所以,_dispatch_queue_init
函数第 4 个参数(initial_state_bits
)传入的值是 DISPATCH_QUEUE_ROLE_INNER
(0x0000000000000000ull
)。
_dispatch_queue_init
函数实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 static inline dispatch_queue_class_t _dispatch_queue_init(dispatch_queue_class_t dqu, dispatch_queue_flags_t dqf, uint16_t width, uint64_t initial_state_bits) { uint64_t dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(width); dispatch_queue_t dq = dqu._dq; dispatch_assert((initial_state_bits & ~(DISPATCH_QUEUE_ROLE_MASK | DISPATCH_QUEUE_INACTIVE)) == 0 ); if (initial_state_bits & DISPATCH_QUEUE_INACTIVE) { dq->do_ref_cnt += 2 ; if (dx_metatype(dq) == _DISPATCH_SOURCE_TYPE) { dq->do_ref_cnt++; } } dq_state |= initial_state_bits; dq->do_next = DISPATCH_OBJECT_LISTLESS; dqf |= DQF_WIDTH(width); os_atomic_store2o(dq, dq_atomic_flags, dqf, relaxed); dq->dq_state = dq_state; dq->dq_serialnum = os_atomic_inc_orig(&_dispatch_queue_serial_numbers, relaxed); return dqu; }
这部分逻辑,重点需要关注 dq_state
、dq_width
的赋值。
dq_state
的赋值比较好理解,其初始值就是:
1 dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(width);
注意,这里的 dq_state
非最终值,后续还有 dq_state
赋值逻辑,在下面“dq 其他配置”部分会继续分析 dq_state
。
dq_width
字段是队列的宽度,存储了队列能够同时处理的任务的数量。关于 dq_width
的赋值,先回头看下 dispatch_queue_t
的数据结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 typedef struct dispatch_queue_s *dispatch_queue_t ;struct dispatch_queue_s { struct dispatch_queue_s *volatile do_next ; struct dispatch_queue_s *do_targetq ; union { uint64_t volatile dq_state; dispatch_lock dq_state_lock; uint32_t dq_state_bits; }; unsigned long dq_serialnum; const char *dq_label; union { uint32_t volatile dq_atomic_flags; struct { const uint16_t dq_width; const uint16_t __dq_opaque2; }; }; }
前面已经提到,联合体中的 dq_atomic_flags
是 32 位的无符号整数类型,其占用了 32 位的内存区域,联合体内部 dq_width
和 __dq_opaque2
分别占用 dq_atomic_flags
的低 16 位和高 16 位。
_dispatch_queue_init
函数中,注意下面这部分逻辑:
1 2 dqf |= DQF_WIDTH(width); os_atomic_store2o(dq, dq_atomic_flags, dqf, relaxed);
其中 DQF_WIDTH
宏定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 DISPATCH_OPTIONS(dispatch_queue_flags, uint32_t , DQF_NONE = 0x00000000 , DQF_AUTORELEASE_ALWAYS = 0x00010000 , DQF_AUTORELEASE_NEVER = 0x00020000 , #define _DQF_AUTORELEASE_MASK 0x00030000 DQF_THREAD_BOUND = 0x00040000 , DQF_BARRIER_BIT = 0x00080000 , DQF_TARGETED = 0x00100000 , DQF_LABEL_NEEDS_FREE = 0x00200000 , DQF_MUTABLE = 0x00400000 , DQF_RELEASED = 0x00800000 , DSF_STRICT = 0x04000000 , DSF_WLH_CHANGED = 0x08000000 , DSF_CANCELED = 0x10000000 , DSF_CANCEL_WAITER = 0x20000000 , DSF_NEEDS_EVENT = 0x40000000 , DSF_DELETED = 0x80000000 , #define DQF_FLAGS_MASK ((dispatch_queue_flags_t)0xffff0000) #define DQF_WIDTH_MASK ((dispatch_queue_flags_t)0x0000ffff) #define DQF_WIDTH(n) ((dispatch_queue_flags_t)(uint16_t)(n)) );
DQF_WIDTH
宏将 width
转换为 dispatch_queue_flags_t
类型,并确保它位于低 16 位。具体来说,DQF_WIDTH
(width
) 通过将 width
强制转换为 uint16_t
,然后再转换为 dispatch_queue_flags_t
,确保宽度值仅影响低 16 位。
也就是说,下述逻辑:
1 dqf |= DQF_WIDTH(width);
将 width
的值设置到 dqf
的低 16 位上。
os_atomic_store2o
宏定义如下:
1 2 3 4 5 #define os_atomic_store2o(p, f, v, m) \ os_atomic_store(&(p)->f, (v), m) #define os_atomic_store(p, v, m) \ atomic_store_explicit(_os_atomic_c11_atomic(p), v, memory_order_##m)
可以定义知道 os_atomic_store2o
宏的作用是将值 dqf
原子地存储到结构体 dq
的字段 dq_atomic_flags
中。
所以,最终 width
值将会赋值给 dispatch_queue_s
中的 dq_width
上,dqf
其他内容存储到 __dq_opaque2
中。
所以最终:
创建串行队列时,dq_width = 1
;
创建并发队列时,dq_width = 4094
;
(4)dq 其他配置 这部分逻辑如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 dq->dq_label = label; dq->dq_priority = _dispatch_priority_make((dispatch_qos_t )dqai.dqai_qos, dqai.dqai_relpri); if (overcommit == _dispatch_queue_attr_overcommit_enabled) { dq->dq_priority |= DISPATCH_PRIORITY_FLAG_OVERCOMMIT; } if (!dqai.dqai_inactive) { _dispatch_queue_priority_inherit_from_target(dq, tq); _dispatch_lane_inherit_wlh_from_target(dq, tq); } _dispatch_retain(tq); dq->do_targetq = tq;
这里主要是对 dq
其他的一些参数的配置,这里重点看下 _dispatch_lane_inherit_wlh_from_target
函数的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 static void _dispatch_lane_inherit_wlh_from_target(dispatch_lane_t dq, dispatch_queue_t tq) { uint64_t old_state, new_state, role; if (!dx_hastypeflag(tq, QUEUE_ROOT)) { role = DISPATCH_QUEUE_ROLE_INNER; } else if (_dispatch_base_lane_is_wlh(dq, tq)) { role = DISPATCH_QUEUE_ROLE_BASE_WLH; } else { role = DISPATCH_QUEUE_ROLE_BASE_ANON; } os_atomic_rmw_loop2o(dq, dq_state, old_state, new_state, relaxed, { new_state = old_state & ~DISPATCH_QUEUE_ROLE_MASK; new_state |= role; if (old_state == new_state) { os_atomic_rmw_loop_give_up(break ); } }); if (_dq_state_is_base_wlh(old_state) && !_dq_state_is_base_wlh(new_state)) { dispatch_deferred_items_t ddi = _dispatch_deferred_items_get(); if (ddi && ddi->ddi_wlh == (dispatch_wlh_t )dq) { _dispatch_event_loop_leave_immediate(new_state); } } if (!dx_hastypeflag(tq, QUEUE_ROOT)) { dispatch_queue_flags_t clear = 0 , set = DQF_TARGETED; if (dx_metatype(tq) == _DISPATCH_WORKLOOP_TYPE) { clear |= DQF_MUTABLE; #if !DISPATCH_ALLOW_NON_LEAF_RETARGET } else { clear |= DQF_MUTABLE; #endif } if (clear) { _dispatch_queue_atomic_flags_set_and_clear(tq, set , clear); } else { _dispatch_queue_atomic_flags_set(tq, set ); } } }
这里主要关注角色位 role
配置,role
最终会参与 dq_state
的赋值 new_state |= role;
。
role
赋值判断逻辑如下:
1 2 3 4 5 6 7 if (!dx_hastypeflag(tq, QUEUE_ROOT)) { role = DISPATCH_QUEUE_ROLE_INNER; } else if (_dispatch_base_lane_is_wlh(dq, tq)) { role = DISPATCH_QUEUE_ROLE_BASE_WLH; } else { role = DISPATCH_QUEUE_ROLE_BASE_ANON; }
dx_hastypeflag
是个宏,根据其源码定义以及 _dispatch_queue_concurrent_vtable
、 _dispatch_queue_serial_vtable
可知,无论串行队列还是并发队列,dx_hastypeflag(tq, QUEUE_ROOT)
都是 true
,所以不会走第一个 if
分支,故会进入 _dispatch_base_lane_is_wlh
函数的判断逻辑。
_dispatch_base_lane_is_wlh
函数实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 static inline bool _dispatch_base_lane_is_wlh(dispatch_lane_t dq, dispatch_queue_t tq) { if (unlikely(!_dispatch_kevent_workqueue_enabled)) { return false ; } if (dx_type(dq) == DISPATCH_QUEUE_NETWORK_EVENT_TYPE) { return true ; } if (dx_metatype(dq) == _DISPATCH_SOURCE_TYPE) { if (likely(!upcast(dq)._ds->ds_refs->du_can_be_wlh)) { return false ; } dispatch_assert(upcast(dq)._ds->ds_refs->du_is_direct); } return dq->dq_width == 1 && _dispatch_is_in_root_queues_array(tq); } static inline bool _dispatch_is_in_root_queues_array(dispatch_queue_class_t dqu) { return (dqu._dgq >= _dispatch_root_queues) && (dqu._dgq < _dispatch_root_queues + _DISPATCH_ROOT_QUEUE_IDX_COUNT); }
上述逻辑中,无论串行队列还是并发队列,_dispatch_is_in_root_queues_array
函数都是返回 true
。所以,最终 _dispatch_base_lane_is_wlh
函数返回值取决于 dq->dq_width == 1
的判断结果,即:
创建串行队列时,返回值为 true
。
role = DISPATCH_QUEUE_ROLE_BASE_WLH;
dq_state = (dq_state | role) = (DISPATCH_QUEUE_STATE_INIT_VALUE(dq_width) | DISPATCH_QUEUE_ROLE_BASE_WLH);
创建并发队列时,返回值为 false
。
role = DISPATCH_QUEUE_ROLE_BASE_ANON;
dq_state = (dq_state | role) = (DISPATCH_QUEUE_STATE_INIT_VALUE(dq_width) | DISPATCH_QUEUE_ROLE_BASE_ANON);
(5)简单总结 总结一下:
串行队列
dq_width = 1;
dq_state = (DISPATCH_QUEUE_STATE_INIT_VALUE(dq_width) | DISPATCH_QUEUE_ROLE_BASE_WLH);
串行队列是 overcommit
的
并发队列
dq_width = 4094
即串行队列最多能同时处理 4094
个任务,但最终有多少个任务能够同时执行,还要看系统资源情况,例如线程池可用线程数量等。
dq_state = (DISPATCH_QUEUE_STATE_INIT_VALUE(dq_width) | DISPATCH_QUEUE_ROLE_BASE_ANON);
并发队列是非 overcommit
的
对于 do_targetq
,串行队列、并发队列的 do_targetq
,都是从根队列数组 _dispatch_root_queues
中取出的对应的根队列(root queue),只不过两者取的 index
不一样。
同时,根据源码中宏定义:
1 2 3 4 5 6 7 8 #define DISPATCH_QUEUE_STATE_INIT_VALUE(width) \ ((DISPATCH_QUEUE_WIDTH_FULL - (width)) << DISPATCH_QUEUE_WIDTH_SHIFT) #define DISPATCH_QUEUE_WIDTH_FULL 0x1000ull #define DISPATCH_QUEUE_WIDTH_SHIFT 41 #define DISPATCH_QUEUE_ROLE_BASE_WLH 0x0000002000000000ull #define DISPATCH_QUEUE_ROLE_BASE_ANON 0x0000001000000000ull
可以计算出:串行队列:
1 dq_state = (DISPATCH_QUEUE_STATE_INIT_VALUE(dq_width) | DISPATCH_QUEUE_ROLE_BASE_WLH) = (DISPATCH_QUEUE_STATE_INIT_VALUE(1 ) | DISPATCH_QUEUE_ROLE_BASE_WLH) = 0x001ffe2000000000 。
并发队列:
1 dq_state = (DISPATCH_QUEUE_STATE_INIT_VALUE(4094 ) | DISPATCH_QUEUE_ROLE_BASE_ANON) = 0x0000041000000000 。
关于 dq_width
、dq_state
,我们可以使用一个 Demo 验证一下:
1 2 3 4 5 6 7 dispatch_queue_t serialQueue = dispatch_queue_create("com.demo.serialQueue" , DISPATCH_QUEUE_SERIAL);dispatch_queue_t concurrentQueue = dispatch_queue_create("com.lixkit.concurrentQueue" , DISPATCH_QUEUE_CONCURRENT);NSLog (@"serialQueue = %@" , [serialQueue debugDescription]);NSLog (@"concurrentQueue = %@" , [concurrentQueue debugDescription]);
运行后打印结果:
上述打印结果中,width
就是 dq_width
:
串行队列 width = 0x1
,转成十进制就是 1
。
并发队列 width = 0xffe
,转成十进制就是 4094
。
打印结果的 state
就是 dq_state
,可以看到打印出的 dq_width
、dq_state
和前面我们根据源码计算出的结果一致。
这里为什么要重点关注 dq_width
、dq_state
、do_targetq
,因为后续 dispatch_sync
、dispatch_async
源码中会用到。