閱讀GCD源碼,首先需要下載libdispatch源碼。很多同學(xué)拿到源碼就直接埋頭苦干,我覺得這樣會像無頭蒼蠅一樣沒有重點,容易懵逼,效率低。相比objc,CFRunloop源碼而言,libdispatch源碼難度比較高。libdispatch源碼中使用了很多宏、且名字特別長、嵌套深、還包含很多os開頭的函數(shù),所以閱讀起來不是那么容易。
本文以問題的形式來窺探源碼,這種方式比較有重點,效率高。
使用GCD的隊列需從創(chuàng)建隊列開始,因此我們源碼分析也從隊列的創(chuàng)建開始分析。
dispatch_queue_create("jensen.cn", NULL);
對于隊列的創(chuàng)建,我們先探索如下2個問題:
1.隊列是如何產(chǎn)生的?
2.串行隊列與并行隊列有什么區(qū)別?
帶著這兩個問題,我們打開源碼找到dispatch_queue_create函數(shù):
#define DISPATCH_TARGET_QUEUE_DEFAULT NULL
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函數(shù)的attr一般傳入DISPATCH_QUEUE_SERIAL、DISPATCH_QUEUE_CONCURRENT或者nil,而宏定義DISPATCH_TARGET_QUEUE_DEFAULT其實就是null
進入_dispatch_lane_create_with_target,這個函數(shù)就是創(chuàng)建隊列的核心函數(shù)。
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)
{
//通過當(dāng)前的屬性獲取屬性信息
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
// Step 1: Normalize arguments (qos, overcommit, tq)
//
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 // !HAVE_PTHREAD_WORKQUEUE_QOS
_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) {
// Handle discrepancies between attr and target queue, attributes win
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 && !tq->do_targetq) {
// target is a pthread or runloop root queue, setting QoS or overcommit
// is disallowed
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) {
// Serial queues default to overcommit!
overcommit = dqai.dqai_concurrent ?
_dispatch_queue_attr_overcommit_disabled :
_dispatch_queue_attr_overcommit_enabled;
}
}
if (!tq) {
tq = _dispatch_get_root_queue(
qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, // 4
overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq; // 0 1
if (unlikely(!tq)) {
DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
}
}
//
// Step 2: Initialize the queue
//
if (legacy) {
// if any of these attributes is specified, use non legacy classes
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) {
// 通過dqai.dqai_concurrent 來區(qū)分并發(fā)和串行
// OS_dispatch_queue_concurrent_class
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;
}
}
// 開辟內(nèi)存 - 生成響應(yīng)的對象 queue
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s));
// 構(gòu)造方法
_dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
(dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
// 標(biāo)簽
dq->dq_label = label;
// 優(yōu)先級
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;
}
代碼中首先通過外部傳入的dqa屬性獲取屬性信息dqai。進入獲取屬性信息的函數(shù)_dispatch_queue_attr_to_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
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);
// 位域?qū)懛? 通過idx不斷的獲取對應(yīng)的值通過取余
// 0000 000000000 00000000000 0000 000 1
//通過位數(shù)來區(qū)分
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 = -(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;
}
如果是參數(shù)dqa為NULL,_dispatch_queue_attr_to_info函數(shù)直接返回dispatch_queue_attr_info_t類型的空結(jié)構(gòu)體。如果不是NULL,蘋果將通過規(guī)定的算法計算出idx,idx采用了位域?qū)懛?通過取余方式獲取對應(yīng)的值,為dqa初始化。
dispatch_queue_attr_info_t類型如下
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;
繼續(xù)閱讀_dispatch_lane_create_with_target函數(shù),我們發(fā)現(xiàn)并行和串行是通過dqai.diqi_concurrent來區(qū)分并行隊列和串行隊列的。
if (dqai.dqai_concurrent) {
// 通過dqai.dqai_concurrent 來區(qū)分并發(fā)和串行
// OS_dispatch_queue_concurrent_class
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
vtable = DISPATCH_VTABLE(queue_serial);
}
查看代碼中DISPATCH_VTABLE的定義:
#define DISPATCH_VTABLE(name) DISPATCH_OBJC_CLASS(name)
#define DISPATCH_OBJC_CLASS(name) (&DISPATCH_CLASS_SYMBOL(name))
#if USE_OBJC
#define DISPATCH_CLASS_SYMBOL(name) OS_dispatch_##name##_class
OS_dispatch_##name##_class,底層將傳入的參數(shù)name,拼接生成對應(yīng)的隊列類,
串行隊列的類為: OS_dispatch_queue_serial_class,并行隊列的類為:OS_dispatch_queue_concurrent_class
if (label) {
const char *tmp = _dispatch_strdup_if_mutable(label);
if (tmp != label) {
dqf |= DQF_LABEL_NEEDS_FREE;
label = tmp;
}
}
// 開辟內(nèi)存 - 生成響應(yīng)的對象 queue
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s));
// 構(gòu)造方法
_dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
(dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
// 標(biāo)簽
dq->dq_label = label;
// 優(yōu)先級
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;
判斷參數(shù)label如果不為NULL,調(diào)用函數(shù)_dispatch_strdup_if_mutable(const char *str)進行處理,判斷如果源字符串是可變的,就重新分配內(nèi)存并拷貝內(nèi)容到內(nèi)存中。否則直接返回。
const char *
_dispatch_strdup_if_mutable(const char *str)
{
#if HAVE_DYLD_IS_MEMORY_IMMUTABLE
size_t size = strlen(str) + 1;
if (unlikely(!_dyld_is_memory_immutable(str, size))) {
char *clone = (char *) malloc(size);
if (dispatch_assume(clone)) {
memcpy(clone, str, size);
}
return clone;
}
return str;
#else
return strdup(str);
#endif
}
處理完成后,判斷是否是原來的那一個label,不一致就替換。
接下來調(diào)用_dispatch_object_alloc函數(shù)為隊列分配內(nèi)存,生成響應(yīng)的對象dq,將隊列包裝成dispatch_lane_t類型。
然后調(diào)用_dispatch_queue_init構(gòu)造函數(shù),為隊列初始化。構(gòu)造方法的參數(shù)width:
#define DISPATCH_QUEUE_WIDTH_FULL 0x1000ull
#define DISPATCH_QUEUE_WIDTH_MAX (DISPATCH_QUEUE_WIDTH_FULL - 2)
// 構(gòu)造方法
_dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
(dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
通過dqai.dqai_concurrent判斷,如果是并行隊列,width為0xffe,十進制為4094,如果是串行隊列則width為1,通過這里我們也就知道為什么并行隊列口子大,串行隊列口子小。
再為dq的所有屬性賦值,dq_label、dq_priority等等。
將自己創(chuàng)建的隊列綁定到root隊列上。
我們注意到在_dispatch_lane_create_with_target函數(shù)在最后調(diào)用了_dispatch_trace_queue_create函數(shù),在_dispatch_trace_queue_create函數(shù)中調(diào)用_dispatch_introspection_queue_create函數(shù),在_dispatch_introspection_queue_create中調(diào)用_dispatch_introspection_queue_create_hook函數(shù),在_dispatch_introspection_queue_create_hook函數(shù)調(diào)用dispatch_introspection_queue_get_info函數(shù)。
#define dx_vtable(x) (&(x)->do_vtable->_os_obj_vtable)
#define dx_metatype(x) (dx_vtable(x)->do_type & _DISPATCH_META_TYPE_MASK)
DISPATCH_USED inline
dispatch_introspection_queue_s
dispatch_introspection_queue_get_info(dispatch_queue_t dq)
{
if (dx_metatype(dq) == _DISPATCH_WORKLOOP_TYPE) {
return _dispatch_introspection_workloop_get_info(upcast(dq)._dwl);
}
return _dispatch_introspection_lane_get_info(upcast(dq)._dl);
}
通過dx_metatype判斷是否為并發(fā)隊列,如果為串行隊列則調(diào)用_dispatch_introspection_workloop_get_info函數(shù),否則調(diào)用_dispatch_introspection_lane_get_info函數(shù)。
static inline dispatch_introspection_queue_s
_dispatch_introspection_workloop_get_info(dispatch_workloop_t dwl)
{
uint64_t dq_state = os_atomic_load2o(dwl, dq_state, relaxed);
dispatch_introspection_queue_s diq = {
.queue = dwl->_as_dq,
.target_queue = dwl->do_targetq,
.label = dwl->dq_label,
.serialnum = dwl->dq_serialnum,
.width = 1,
.suspend_count = 0,
.enqueued = _dq_state_is_enqueued(dq_state),
.barrier = _dq_state_is_in_barrier(dq_state),
.draining = 0,
.global = 0,
.main = 0,
};
return diq;
}
static inline dispatch_introspection_queue_s
_dispatch_introspection_lane_get_info(dispatch_lane_class_t dqu)
{
dispatch_lane_t dq = dqu._dl;
bool global = _dispatch_object_is_global(dq);
uint64_t dq_state = os_atomic_load2o(dq, dq_state, relaxed);
dispatch_introspection_queue_s diq = {
.queue = dq->_as_dq,
.target_queue = dq->do_targetq,
.label = dq->dq_label,
.serialnum = dq->dq_serialnum,
.width = dq->dq_width,
.suspend_count = _dq_state_suspend_cnt(dq_state) + dq->dq_side_suspend_cnt,
.enqueued = _dq_state_is_enqueued(dq_state) && !global,
.barrier = _dq_state_is_in_barrier(dq_state) && !global,
.draining = (dq->dq_items_head == (void*)~0ul) ||
(!dq->dq_items_head && dq->dq_items_tail),
.global = global,
.main = dx_type(dq) == DISPATCH_QUEUE_MAIN_TYPE,
};
return diq;
}
函數(shù)中將傳入的隊列用dispatch_introspection_queue_s這個類型重新包裝,重新賦值。
typedef struct dispatch_introspection_queue_s {
dispatch_queue_t queue;
dispatch_queue_t target_queue;
const char *label;
unsigned long serialnum;
unsigned int width;
unsigned int suspend_count;
unsigned long enqueued:1,
barrier:1,
draining:1,
global:1,
main:1;
} dispatch_introspection_queue_s;
至此,我們已經(jīng)了解隊列創(chuàng)建的整個過程,以及代碼中是如何區(qū)別串行隊列和并行隊列。下面我們來驗證一下:
dispatch_queue_t queueSer = dispatch_queue_create("com.jensen.ser", NULL);
dispatch_queue_t queueCon = dispatch_queue_create("com.jensen.con", DISPATCH_QUEUE_CONCURRENT);
通過lldb,我們分別打印queueSer和queueCon隊列:

打印結(jié)果中,我們看到串行隊列和并行隊列的類分別是OS_dispatch_queue_serial和OS_dispatch_queue_concurrent,label分別是調(diào)用時傳入的參數(shù)com.jensen.ser和com.jensen.con,width分別為0x1和0xffe,與我們代碼分析的結(jié)果一致。
但是我們還是有疑問,串行隊列和并行隊列的target分別為com.apple.root.default-qos.overcommit和com.apple.root.default-qos,這個是如何區(qū)別并關(guān)聯(lián)的呢?帶著這個問題我們繼續(xù)分析。
其實這個target跟我們上述提到的,將自己創(chuàng)建的隊列綁定到root隊列有關(guān)系。
dq->do_targetq = tq;
那么我們要弄清楚target, 那么就必須從獲取root隊列的函數(shù)入手。
#define DISPATCH_QOS_UNSPECIFIED ((dispatch_qos_t)0)
#define DISPATCH_QOS_MAINTENANCE ((dispatch_qos_t)1)
#define DISPATCH_QOS_BACKGROUND ((dispatch_qos_t)2)
#define DISPATCH_QOS_UTILITY ((dispatch_qos_t)3)
#define DISPATCH_QOS_DEFAULT ((dispatch_qos_t)4)
#define DISPATCH_QOS_USER_INITIATED ((dispatch_qos_t)5)
#define DISPATCH_QOS_USER_INTERACTIVE ((dispatch_qos_t)6)
#define DISPATCH_QOS_MIN DISPATCH_QOS_MAINTENANCE
#define DISPATCH_QOS_MAX DISPATCH_QOS_USER_INTERACTIVE
#define DISPATCH_QOS_SATURATED ((dispatch_qos_t)15)
if (!tq) {
tq = _dispatch_get_root_queue(
qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, // 4
overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq; // 0 1
if (unlikely(!tq)) {
DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
}
}
往上查看發(fā)現(xiàn)dispatch_qos_t qos = dqai.dqai_qos 代碼, 那么我們得出當(dāng)隊列是串行隊列qos為DISPATCH_QOS_UNSPECIFIED,_dispatch_get_root_queue函數(shù)傳入的第一個參數(shù)為DISPATCH_QOS_DEFAULT,否則為qos本身。第二個參數(shù)為overcommit == _dispatch_queue_attr_overcommit_enabled,是一個bool,要那么是0,要么是1。跟進_dispatch_get_root_queue函數(shù):
static inline dispatch_queue_global_t
_dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit)
{
if (unlikely(qos < DISPATCH_QOS_MIN || qos > DISPATCH_QOS_MAX)) {
DISPATCH_CLIENT_CRASH(qos, "Corrupted priority");
}
// 4-1= 3
// 2*3+0/1 = 6/7
return &_dispatch_root_queues[2 * (qos - 1) + overcommit];
}
當(dāng)為串行隊列時,qos為4,overcommit為0/1,2 * (qos - 1) + overcommit 的下標(biāo)為2*(4-1)+0/1 = 6/7.
我們找到dispatch_root_queues數(shù)組的初始化如下:
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_queues靜態(tài)數(shù)組的初始化,我們知道target queue其實 是一些已經(jīng)確定的值。那么上述得出的下標(biāo)6/7,在dispatch_root_queues靜態(tài)數(shù)組可查到target queue的label為com.apple.root.default-qos或者com.apple.root.default-qos.overcommit。
我們已經(jīng)了解隊列創(chuàng)建時,root target是如何關(guān)聯(lián)的了。我們聯(lián)想到系統(tǒng)默認(rèn)幫我們創(chuàng)建的主隊列dispatch_get_main_queue()和全局并發(fā)隊列dispatch_get_global_queue(0, 0)又是怎么樣的呢?
帶著問題,我們先通過lldb打印主隊列信息和全局隊列的信息。
dispatch_queue_t queueMain = dispatch_get_main_queue();
dispatch_queue_t queueglob = dispatch_get_global_queue(0, 0);

進入dispatch_get_main_queue()dispatch_get_main_queue()源碼,
#define DISPATCH_GLOBAL_OBJECT(type, object) ((OS_OBJECT_BRIDGE type)&(object))
dispatch_queue_main_t
dispatch_get_main_queue(void)
{
return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
}
dispatch_queue_main_t是dispatch_queue_static_s類型的結(jié)構(gòu)體指針。
typedef struct dispatch_queue_static_s *dispatch_queue_main_t;
我們可以查看dispatch_queue_main_t如何創(chuàng)建的
DISPATCH_DECL_SUBCLASS(dispatch_queue_main, dispatch_queue_serial);
#define DISPATCH_DECL_SUBCLASS(name, base) OS_OBJECT_DECL_SUBCLASS(name, base)
#define OS_OBJECT_DECL_SUBCLASS(name, super) \
OS_OBJECT_DECL_IMPL(name, <OS_OBJECT_CLASS(super)>)
#define OS_OBJECT_DECL_IMPL(name, ...) \
OS_OBJECT_DECL_PROTOCOL(name, __VA_ARGS__) \
typedef NSObject<OS_OBJECT_CLASS(name)> \
* OS_OBJC_INDEPENDENT_CLASS name##_t
從上述得知,dispatch_queue_main是繼承dispatch_queue_serial, 并重寫dispatch_queue_serial的函數(shù)。這就追溯到我們最開始的串行隊列創(chuàng)建。
這里傳入dispatch_queue_main,所以主隊列的底層類就是OS_dispatch_queue_main_class,與我們的打印也是一致的。
_dispatch_main_q的初始化如下:
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,
};
在_dispatch_main_q的初始化中,我們可以看到主隊列的label為com.apple.main-thread,這就可以說明為什么主隊列的label為com.apple.main-thread。
上述代碼中可以看到主隊列的targetq為_dispatch_get_default_queue(true),
#define _dispatch_get_default_queue(overcommit) \
_dispatch_root_queues[DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS + \
!!(overcommit)]._as_dq
可以看到主隊列的target是直接從靜態(tài)數(shù)組_dispatch_root_\queues取值的。
enum {
DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS = 0,
DISPATCH_ROOT_QUEUE_IDX_MAINTENANCE_QOS_OVERCOMMIT,
DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS,
DISPATCH_ROOT_QUEUE_IDX_BACKGROUND_QOS_OVERCOMMIT,
DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS,
DISPATCH_ROOT_QUEUE_IDX_UTILITY_QOS_OVERCOMMIT,
DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS,
DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS_OVERCOMMIT,
DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS,
DISPATCH_ROOT_QUEUE_IDX_USER_INITIATED_QOS_OVERCOMMIT,
DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS,
DISPATCH_ROOT_QUEUE_IDX_USER_INTERACTIVE_QOS_OVERCOMMIT,
_DISPATCH_ROOT_QUEUE_IDX_COUNT,
};
從枚舉中得知DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS為6,因此下標(biāo)為7,查找靜態(tài)數(shù)組得知下標(biāo)為7的target的``label為com.apple.root.default-qos.overcommit,與我們例子打印出的一致。
我們已經(jīng)弄清楚了主隊列是怎么回事了。接下來我們繼續(xù)分析全局隊列dispatch_get_global_queue(0, 0)。
dispatch_queue_global_t
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;
}
return _dispatch_get_root_queue(qos, flags & DISPATCH_QUEUE_OVERCOMMIT);
}
dispatch_get_global_queue(long priority, unsigned long flags)函數(shù)中調(diào)用_dispatch_qos_from_queue_priority(long priority),通過priority獲取qos
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QOS_DEFAULT ((dispatch_qos_t)4)
DISPATCH_ALWAYS_INLINE
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);
}
}
例子中輸入的priority為0,得出qos為4.
最后調(diào)用函數(shù)_dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit)直接獲得隊列。
_dispatch_get_root_queue(dispatch_qos_t qos, bool overcommit)
{
if (unlikely(qos < DISPATCH_QOS_MIN || qos > DISPATCH_QOS_MAX)) {
DISPATCH_CLIENT_CRASH(qos, "Corrupted priority");
}
return &_dispatch_root_queues[2 * (qos - 1) + overcommit];
}
通過靜態(tài)數(shù)組找到下標(biāo)為6,就是全局并發(fā)隊列的label。
#define DISPATCH_QUEUE_WIDTH_POOL (DISPATCH_QUEUE_WIDTH_FULL - 1)
#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__ \
}
通過上述我們可以知道全局并發(fā)隊列的width為DISPATCH_QUEUE_WIDTH_FULL - 1,0xfff,比我們自己創(chuàng)建的自定義隊列0xffe多1。
通過上述分析我們也總結(jié)出全局并發(fā)隊列和自定義并發(fā)隊列的區(qū)別在于:
全局并發(fā)隊列直接從靜態(tài)數(shù)組中取出,而自定義全局隊列需手動alloc,并關(guān)聯(lián)root隊列。全局并發(fā)隊列width為0xfff,而自定義并發(fā)隊列的width為0ffe。
總結(jié):本文通過問題的方式簡要探索gcd關(guān)于隊列創(chuàng)建函數(shù)dispatch_queue_create(const char *_Nullable label, dispatch_queue_attr_t _Nullable attr),主隊列dispatch_get_main_queue(void),全局并發(fā)隊列dispatch_get_global_queue(long identifier, unsigned long flags)的源碼。gcd源碼難度較大,本位僅僅只是對一些要點進行指出。本文中可能存在說明不妥當(dāng)?shù)牡胤?希望大牛們多多指教!