23期_iOS_GCD的队列源码研读
2023-08-24 本文已影响0人
萧修
源码研读:
[源码地址]https://opensource.apple.com/releases/)
主队列
我们通过断点nslog,并在控制台bt,可知gcd引自库
libdispatch.dylib
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"GCD函数分析");
});
以下是堆栈的打印信息。
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x000000010014ddd4 005-GCD-源发研读`__29-[ViewController viewDidLoad]_block_invoke(.block_descriptor=0x00000001001500a0) at ViewController.m:22:9
frame #1: 0x000000010071c528 libdispatch.dylib`_dispatch_call_block_and_release + 24
frame #2: 0x000000010071dd50 libdispatch.dylib`_dispatch_client_callout + 16
frame #3: 0x000000010072e808 libdispatch.dylib`_dispatch_main_queue_drain + 1316
frame #4: 0x000000010072e2d4 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 40
frame #5: 0x000000018039a784 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
frame #6: 0x0000000180394de4 CoreFoundation`__CFRunLoopRun + 1912
frame #7: 0x0000000180394254 CoreFoundation`CFRunLoopRunSpecific + 584
frame #8: 0x0000000188eb7c9c GraphicsServices`GSEventRunModal + 160
frame #9: 0x000000010761eff0 UIKitCore`-[UIApplication _run] + 868
frame #10: 0x0000000107622f3c UIKitCore`UIApplicationMain + 124
frame #11: 0x000000010014e02c 005-GCD-源发研读`main(argc=1, argv=0x000000016fcb1b38) at main.m:17:12
frame #12: 0x00000001002dd514 dyld_sim`start_sim + 20
frame #13: 0x00000001004e5f28 dyld`start + 2236
(lldb)
dispatch_get_main_queue是通过DISPATCH_GLOBAL_OBJECT返回
DISPATCH_INLINE DISPATCH_ALWAYS_INLINE DISPATCH_CONST DISPATCH_NOTHROW
dispatch_queue_main_t
dispatch_get_main_queue(void)
{
return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
}
//查看此宏定义
#define DISPATCH_GLOBAL_OBJECT(type, object) ((type)&(object))
- _dispatch_main_q
查看第二个参数,下面列了此参数的结构,通过上面的打印com.apple.main-thread,也可从源码中进行搜索
struct dispatch_queue_static_s _dispatch_main_q = {
DISPATCH_GLOBAL_OBJECT_HEADER(queue_main),
#if !DISPATCH_USE_RESOLVERS
.do_targetq = _dispatch_get_default_queue(true),
#endif
.dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(1) |
DISPATCH_QUEUE_ROLE_BASE_ANON,
.dq_label = "com.apple.main-thread",
.dq_atomic_flags = DQF_THREAD_BOUND | DQF_WIDTH(1),
.dq_serialnum = 1,
};
- 主队列初始化在libdispatchinit()中
- 获取默认队列,将主队列和当前队列和主线程绑定
DISPATCH_EXPORT DISPATCH_NOTHROW
void
libdispatch_init(void)
{
#if DISPATCH_USE_RESOLVERS // rdar://problem/8541707
_dispatch_main_q.do_targetq = _dispatch_get_default_queue(true);
#endif
_dispatch_queue_set_current(&_dispatch_main_q);
_dispatch_queue_set_bound_thread(&_dispatch_main_q);
}
串行队列和并发队列
通过搜索dispatch_queue_create定位到queue.c文件
返回了_dispatch_lane_create_with_target
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_NOINLINE
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);
//根据队列类型创建dqai、dqa传入的属性串行还是并行
//申请开辟内存
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s));
//初始化队列,判断是否并发,是的话传DISPATCH_QUEUE_WIDTH_MAX,否则传1。即串行队列传1
_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_attr_to_infod
qai,在这里进行了dqai的初始化,并判断队列类型
queue的info信息判断,根据传入的队列是串行还是并发
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 DISPATCH_VARIANT_STATIC
if (dqa == &_dispatch_queue_attr_concurrent) {
dqai.dqai_concurrent = true;
return dqai;
}
#endif
-
_dispatch_queue_init
队列初始化函数 -
dq_width
width此值为前面传过来的值,赋值qf |= DQF_WIDTH(width),DISPATCH_QUEUE_WIDTH_MAX或者1,区分串行队列和并发队列
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; // rdar://8181908 see _dispatch_lane_resume
if (dx_metatype(dq) == _DISPATCH_SOURCE_TYPE) {
dq->do_ref_cnt++; // released when DSF_DELETED is set
}
}
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;
}
- vtable
接下来分析vtable,构造末模板,根据dqai中dqai_concurrent,区分队列类型,
DISPATCH_NOINLINE
static dispatch_queue_t
_dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
dispatch_queue_t tq, bool legacy)
{
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);
}
}
// DISPATCH_VTABLE定义
#define DISPATCH_VTABLE(name) DISPATCH_OBJC_CLASS(name)
// vtable symbols - 模板
#define DISPATCH_OBJC_CLASS(name) (&DISPATCH_CLASS_SYMBOL(name))
// 拼接形成类
#define DISPATCH_CLASS_SYMBOL(name) OS_dispatch_##name##_class
并发队列:
传queue_concurrent参数,最终拼接后,队列类型对应的类为:OS_dispatch_queue_concurrent
串行队列:
传queue_serial参数,最终拼接后,队列类型对应的类为:OS_dispatch_queue_serial
所以vtable对应的就是队列的类型。通过拼接完成类的定义
全局队列
服务质量
* - QOS_CLASS_USER_INTERACTIVE
* - QOS_CLASS_USER_INITIATED
* - QOS_CLASS_DEFAULT
* - QOS_CLASS_UTILITY
* - QOS_CLASS_BACKGROUND
优先级
- DISPATCH_QUEUE_PRIORITY_HIGH: QOS_CLASS_USER_INITIATED
* - DISPATCH_QUEUE_PRIORITY_DEFAULT: QOS_CLASS_DEFAULT
* - DISPATCH_QUEUE_PRIORITY_LOW: QOS_CLASS_UTILITY
* - DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND
类
API_AVAILABLE(macos(10.6), ios(4.0))
DISPATCH_EXPORT DISPATCH_CONST DISPATCH_WARN_RESULT DISPATCH_NOTHROW
dispatch_queue_global_t
dispatch_get_global_queue(intptr_t identifier, uintptr_t flags);
系统维护一个全局队列集合,根据不同服务质量和优先级提供不同并发队列