【iOS多线程】DispatchQueue原理解析之队列

510 阅读3分钟

本文是作者在学习iOS底层代码时所著,文章中会尽量使用确定性的词汇,旨在帮助想要轻度深入的读者能够快速了解iOS底层实现。文章中内容的逻辑自洽,但内容的正确性需要读者自行甄别,仅供参考。

在之前的文章中,我们学习了队列创建异步任务创建执行的原理,在这个过程中,我们多次提到主队列、全局队列、自定义队列、root队列等等。这篇文章我们一起来看看,这些队列究竟是什么?

队列

主队列

要知道主队列是什么,我们需要知道,当我们在执行DispatchQueue.main时,我们在做什么,

public class var main: DispatchQueue {
    return _swift_dispatch_get_main_queue()
}

继续看_swift_dispatch_get_main_queue

static inline dispatch_queue_t
_swift_dispatch_get_main_queue(void) {
  return dispatch_get_main_queue();
}

继续看dispatch_get_main_queue

dispatch_queue_main_t
dispatch_get_main_queue(void)
{
	// DISPATCH_GLOBAL_OBJECT是一个强转的宏,把后面的参数的类型转成前面的类型
	return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
}

继续看_dispatch_main_q

struct dispatch_queue_static_s _dispatch_main_q = {
	// 配置queue_main的vtable
	DISPATCH_GLOBAL_OBJECT_HEADER(queue_main),
#if !DISPATCH_USE_RESOLVERS
	// 获取.default状态的overcommit的root队列
	.do_targetq = _dispatch_get_default_queue(true),
#endif
	.dq_state = DISPATCH_QUEUE_STATE_INIT_VALUE(1) |
			DISPATCH_QUEUE_ROLE_BASE_ANON,
	// debug信息中常出现的label
	.dq_label = "com.apple.main-thread",
	// DQF_WIDTH(1)代表是串行队列
	.dq_atomic_flags = DQF_THREAD_BOUND | DQF_WIDTH(1),
	// 序号,之前我们获取的root队列序号是从3-15,主队列序号为1
	.dq_serialnum = 1,
};

从这里可以看出,主队列是序号为1,label为com.apple.main-thread,targettq为默认的过载root队列,这样的队列。它在执行任务时创建的线程,就是我们熟悉的主线程。

全局队列

全局队列是我们日常使用中频率很高的队列,我们一起来看看DispatchQueue.global()做了什么,

public class func global(qos: DispatchQoS.QoSClass = .default) -> DispatchQueue {
    return __dispatch_get_global_queue(Int(qos.rawValue.rawValue), 0)
}

继续看__dispatch_get_global_queue

dispatch_get_global_queue(intptr_t priority, uintptr_t 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;
	}
	// 前面都是在配置qos的值,
	// 到这里可以看到是根据qos和flags,从root队列中取出一个队列返回
	return _dispatch_get_root_queue(qos, flags & DISPATCH_QUEUE_OVERCOMMIT);
}

可以看出,全局队列就是其中一个root队列。

自定义队列

异步任务创建执行这篇文章中,就是以自定义队列为基础来讲的,

let queue = DispatchQueue(label: "com.concurrent", attributes: .concurrent)

swift代码中创建的queue确实是自定义的队列,但最终执行任务时,也是root队列在执行。

root队列

说了这么久的root队列,那么root队列到底是什么呢?

struct dispatch_queue_global_s _dispatch_root_queues[] = {
#define _DISPATCH_ROOT_QUEUE_IDX(n, flags) \
		((flags & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) ? \
		DISPATCH_ROOT_QUEUE_IDX_##n##_QOS_OVERCOMMIT : \
		DISPATCH_ROOT_QUEUE_IDX_##n##_QOS)
#define _DISPATCH_ROOT_QUEUE_ENTRY(n, flags, ...) \
	[_DISPATCH_ROOT_QUEUE_IDX(n, flags)] = { \
		DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), \
		.dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, \
		.do_ctxt = _dispatch_root_queue_ctxt(_DISPATCH_ROOT_QUEUE_IDX(n, flags)), \
		.dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), \
		.dq_priority = flags | ((flags & DISPATCH_PRIORITY_FLAG_FALLBACK) ? \
				_dispatch_priority_make_fallback(DISPATCH_QOS_##n) : \
				_dispatch_priority_make(DISPATCH_QOS_##n, 0)), \
		__VA_ARGS__ \
	}
	_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, 0,
		.dq_label = "com.apple.root.maintenance-qos",
		.dq_serialnum = 4,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.maintenance-qos.overcommit",
		.dq_serialnum = 5,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, 0,
		.dq_label = "com.apple.root.background-qos",
		.dq_serialnum = 6,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.background-qos.overcommit",
		.dq_serialnum = 7,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, 0,
		.dq_label = "com.apple.root.utility-qos",
		.dq_serialnum = 8,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.utility-qos.overcommit",
		.dq_serialnum = 9,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT, DISPATCH_PRIORITY_FLAG_FALLBACK,
		.dq_label = "com.apple.root.default-qos",
		.dq_serialnum = 10,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT,
			DISPATCH_PRIORITY_FLAG_FALLBACK | DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.default-qos.overcommit",
		.dq_serialnum = 11,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, 0,
		.dq_label = "com.apple.root.user-initiated-qos",
		.dq_serialnum = 12,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.user-initiated-qos.overcommit",
		.dq_serialnum = 13,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, 0,
		.dq_label = "com.apple.root.user-interactive-qos",
		.dq_serialnum = 14,
	),
	_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
		.dq_label = "com.apple.root.user-interactive-qos.overcommit",
		.dq_serialnum = 15,
	),
};

根据这个宏_DISPATCH_ROOT_QUEUE_ENTRY

#define _DISPATCH_ROOT_QUEUE_ENTRY(n, flags, ...) \
[_DISPATCH_ROOT_QUEUE_IDX(n, flags)] = { \
    DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), \
    .dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, \
    .do_ctxt = _dispatch_root_queue_ctxt(_DISPATCH_ROOT_QUEUE_IDX(n, flags)), \
    .dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), \
    .dq_priority = flags | ((flags & DISPATCH_PRIORITY_FLAG_FALLBACK) ? \
            _dispatch_priority_make_fallback(DISPATCH_QOS_##n) : \
            _dispatch_priority_make(DISPATCH_QOS_##n, 0)), \
    __VA_ARGS__ \
}

我们可以看到,所谓的root队列,就是一些带有特定参数的队列。在执行各种逻辑(sync,async,group等等)中,根据各个参数的不同,产生不同的逻辑。

结语

由于能力有限,文章中难免出现疏漏或者根本性错误,欢迎指正。

如果文章对您有帮助,可以点个赞支持一下,谢谢!