GCD簡介
什么是GCD?
全稱是 Grand Central Dispatch
純 C 語言,提供了非常多強大的函數(shù) GCD的優(yōu)勢
GCD 是蘋果公司為多核的并行運算提出的解決方案
GCD 會自動利用更多的CPU內核(比如雙核、四核)
GCD 會自動管理線程的生命周期(創(chuàng)建線程、調度任務、銷毀線程) 程序員只需要告訴 GCD 想要執(zhí)行什么任務,不需要編寫任何線程管理代碼
函數(shù)
將任務添加到隊列,并且指定執(zhí)行任務的函數(shù)
任務使用 block 封裝
- 任務的 block 沒有參數(shù)也沒有返回值
- 執(zhí)行任務的函數(shù)
- 異步
dispatch_async - 不用等待當前語句執(zhí)行完畢,就可以執(zhí)行下一條語句 * 會開啟線程執(zhí)行 block 的任務
- 異步是多線程的代名詞
- 同步
dispatch_sync - 必須等待當前語句執(zhí)行完畢,才會執(zhí)行下一條語
句 - 不會開啟線程
- 在當前執(zhí)行 block 的任務
隊列

隊列的創(chuàng)建
#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);
}
其參數(shù)如下:
const char *label: 隊列的唯一標識符,可以傳空值。
dispatch_queue_attr_t attr: 標識隊列的類型,區(qū)分是串行隊列還是并發(fā)隊列。
DISPATCH_QUEUE_SERIAL: 串行隊列
DISPATCH_QUEUE_CONCURRENT: 并發(fā)隊列
串行隊列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("serial_queue", DISPATCH_QUEUE_SERIAL);
常用的主隊列就是串行隊列,dispatch_get_main_queue()
專門用在主線程調度任務的隊列,也稱UI隊列
不會再開啟線程
如果有任務執(zhí)行,再添加其他任務,會被堵塞
并發(fā)隊列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
常用的全局隊列就是并發(fā)隊列dispatch_get_global_queue(long identifier, unsigned long flags),它可以直接執(zhí)行異步任務。該方法第一個參數(shù)是優(yōu)先級,全局隊列的優(yōu)先級為DISPATCH_QUEUE_PRIORITY_DEFAULT,這個值是一個為0的宏,所以也可以傳0。unsigned long flags: 蘋果官方文檔的解釋是Flags that are reserved for future use。標記這個參數(shù)是為了未來使用保留的,現(xiàn)在傳0即可。
此處引入線程的優(yōu)先級概念,優(yōu)先級越高越先執(zhí)行。
DISPATCH_QUEUE_PRIORITY_HIGH: 2
DISPATCH_QUEUE_PRIORITY_DEFAULT: 0
DISPATCH_QUEUE_PRIORITY_LOW: (-2)
DISPATCH_QUEUE_PRIORITY_BACKGROUND: INT16_MIN
隊列和函數(shù)組合

看下例子一
dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
// 異步函數(shù)
dispatch_async(queue, ^{
NSLog(@"2");
NSLog(@"4");
dispatch_sync(queue, ^{
NSLog(@"3");
});
});
NSLog(@"5");
打印結果為1,5,2,4,3,先是順序執(zhí)行,異步隊列不會阻塞,但是會耗時,所以會慢些
例子二,選擇題
dispatch_queue_t queue = dispatch_queue_create("com.lg.cooci.cn", DISPATCH_QUEUE_CONCURRENT);
/***
1 2 3
0
7 8 9
*/
dispatch_async(queue, ^{
// sleep(2);
NSLog(@"1");
});
dispatch_async(queue, ^{
NSLog(@"2");
});
// 堵塞 - 護犢子
dispatch_sync(queue, ^{
NSLog(@"3");
});
// **********************
NSLog(@"0");
dispatch_async(queue, ^{
NSLog(@"7");
});
dispatch_async(queue, ^{
NSLog(@"8");
});
dispatch_async(queue, ^{
NSLog(@"9");
});
// A: 1230789
// B: 1237890
// C: 3120798
// D: 2137890
答案AC,1,2開啟異步線程,代碼在137行堵塞,阻塞耗時比異步隊列耗時久,所以0在1,2,3之后運行,0在主線程,7,8,9在它之后開啟異步線程,耗時,所以0在7,8,9之前
例子三
// 同步隊列
dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
// 異步函數(shù)
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
打印結果,1,5,2,產(chǎn)生死鎖崩潰,首先是一個串行隊列,1,5線執(zhí)行,然后執(zhí)行異步函數(shù)里的任務,2,同步代碼塊,4,在4這里產(chǎn)生阻塞,需要等同步代碼塊執(zhí)行完,同步代碼塊里有任務3,但是串行隊列的原則是先進先出,所以3需要等4任務執(zhí)行完后才能執(zhí)行,產(chǎn)生死鎖。

如果把4任務提前會死鎖嗎
// 同步隊列
dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
// 異步函數(shù)
dispatch_async(queue, ^{
NSLog(@"2");
NSLog(@"4");
dispatch_sync(queue, ^{
NSLog(@"3");
});
});
NSLog(@"5");
打印結果 1,5,2,4,崩潰,因為任務3和異步函數(shù)形成相互等待,使用方面要特別注意串行隊列和同步函數(shù)。判斷是否發(fā)生死鎖的最好方法就是看有沒有在串行隊列(當然也包括主隊列)中向這個隊列添加任務。
死鎖
? 主線程因為你同步函數(shù)的原因等著先執(zhí)行任務
? 主隊列等著主線程的任務執(zhí)行完畢再執(zhí)行自己的任務
? 主隊列和主線程相互等待會造成死鎖
隊列是如何創(chuàng)建的
我們通過dispatch_queue_create創(chuàng)建隊列,我們點進去發(fā)現(xiàn)看不到其他的,需要配合源碼分析,首先我們在dispatch_queue_create處下一個dispatch_queue_create的符號斷點,可以看到它在libdispatch動態(tài)庫里面,在Apple open source里下載對應的源碼。

打開源碼,搜索dispatch_queue_create( 發(fā)現(xiàn)搜出來很多,因為我們穿的第一個參數(shù)是字符串,搜索dispatch_queue_create(con,結果如下

來到這里
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_lane_create_with_target

QOS:類似于優(yōu)先級,在創(chuàng)建global queue的時候的第一個參數(shù)就是priority或者QOS。
over commit:如果當前隊列沒有可以分配的空余線程,就開啟一個新線程來做任務
我們創(chuàng)建隊列主要是通過第二個參數(shù)區(qū)分是串行還是并行,也就是重點在于dispatch_queue_attr_t dqa這里。
搜索_dispatch_queue_attr_to_info方法,來到這里
ispatch_queue_attr_info_t
_dispatch_queue_attr_to_info(dispatch_queue_attr_t dqa)
{
dispatch_queue_attr_info_t dqai = { };
//默認是串行隊列,如果傳NULL返回
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);
// 位域
// 0000 000000000 00000000000 0000 000 1
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;
}
第一句代碼就是將我們的外界傳進來區(qū)分串行還是并發(fā)的參數(shù)傳進去創(chuàng)建了一個 dispatch_queue_attr_info_t 類型的結構體。
一查 dispatch_queue_attr_info_t 是一個結構體位域,結構體位域可以通過一些位運算取出我們想要的內容,過濾掉我們不想要的數(shù)據(jù)。
1.串行隊列傳的是NULL ,所以直接返回.
2.并行隊列,通過按位取余設置下面的各個參數(shù)
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;
回到原來的方法_dispatch_lane_create_with_target繼續(xù)分析
static dispatch_queue_t
_dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
dispatch_queue_t tq, bool legacy)
{
////其實就是把attr轉化為{}字典形式的attr集合,dqa里面會有qos,overcommit,inactive,concurrent之類的key和value
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;
}
}
// 開辟內存 - 生成響應的對象 queue
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;
// 優(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;
}
通過dqai.dqai_concurrent 來區(qū)分并發(fā)和串行。_dispatch_queue_attr_overcommit_enabled串行,_dispatch_queue_attr_overcommit_disabled并發(fā)
overcommit = dqai.dqai_concurrent ?
_dispatch_queue_attr_overcommit_disabled :
_dispatch_queue_attr_overcommit_enabled;
dispatch_object_t
這里通過_dispatch_object_alloc開辟內存,那我們看一下dispatch_object_t的內容。
一般通過繼承實現(xiàn)多態(tài),這里通過聯(lián)合體的方式,包含了很多類型,避免開辟太多空間,是互斥的,同一時間只能有一個有效
typedef struct dispatch_object_s {
private:
dispatch_object_s();
~dispatch_object_s();
dispatch_object_s(const dispatch_object_s &);
void operator=(const dispatch_object_s &);
} *dispatch_object_t;
#define DISPATCH_DECL(name) \
typedef struct name##_s : public dispatch_object_s {} *name##_t
#define DISPATCH_DECL_SUBCLASS(name, base) \
typedef struct name##_s : public base##_s {} *name##_t
#define DISPATCH_GLOBAL_OBJECT(type, object) (static_cast<type>(&(object)))
#define DISPATCH_RETURNS_RETAINED
#else /* Plain C */
#ifndef __DISPATCH_BUILDING_DISPATCH__
typedef union {
struct _os_object_s *_os_obj;
struct dispatch_object_s *_do;
struct dispatch_queue_s *_dq;
struct dispatch_queue_attr_s *_dqa;
struct dispatch_group_s *_dg;
struct dispatch_source_s *_ds;
struct dispatch_mach_s *_dm;
struct dispatch_mach_msg_s *_dmsg;
struct dispatch_semaphore_s *_dsema;
struct dispatch_data_s *_ddata;
struct dispatch_io_s *_dchannel;
} dispatch_object_t DISPATCH_TRANSPARENT_UNION;
這里我們看一個例子。
// com.apple.root.default-qos width = 0xffe
// com.apple.root.default-qos.overcommit width = 0x1 = 1
// 隊列 - 模板 _dispatch_root_queues里面取值
// _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_init
// _dispatch_root_queues init
// width = 0xfff
// 自定義: 0xffe
dispatch_queue_t queue1 = dispatch_queue_create("cooci", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("KC", NULL);
NSLog(@"%@",dispatch_get_main_queue());
NSLog(@"%@",dispatch_get_global_queue(0, 0));
NSLog(@"%@-%@",queue1,queue2);
打印結果如下
2020-08-23 22:47:45.560834+0800 001---函數(shù)與隊列[95788:1954758] 來了 master
2020-08-23 22:47:45.561110+0800 001---函數(shù)與隊列[95788:1954758] <OS_dispatch_queue_main: com.apple.main-thread>
2020-08-23 22:47:45.561291+0800 001---函數(shù)與隊列[95788:1954758] <OS_dispatch_queue_global: com.apple.root.default-qos>
2020-08-23 22:47:45.561472+0800 001---函數(shù)與隊列[95788:1954758] <OS_dispatch_queue_concurrent: cooci>-<OS_dispatch_queue_serial: KC>
(lldb) po queue1
<OS_dispatch_queue_concurrent: cooci[0x600003686600] = { xref = 1, ref = 1, sref = 1, target = com.apple.root.default-qos[0x105530f00], width = 0xffe, state = 0x0000041000000000, in-flight = 0}>
(lldb) po quere2
error: use of undeclared identifier 'quere2'
(lldb) po queue2
<OS_dispatch_queue_serial: KC[0x600003686700] = { xref = 1, ref = 1, sref = 1, target = com.apple.root.default-qos.overcommit[0x105530f80], width = 0x1, state = 0x001ffe2000000000, in-flight = 0}>
通過上面分析我們可以看到一個com.apple.root.default-qos,width = 0xffe,為并發(fā)隊列,一個com.apple.root.default-qos.overcommit,width = 0x1 = 1為串行隊列。DISPATCH_QUEUE_WIDTH_MAX是通過源碼知道是一個宏定義,等于0x1000減2,結果為0xffe。中間有一個宏DISPATCH_QUEUE_WIDTH_POOL 為0x1000減一,所以這里是減2。

// 構造方法
_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_get_root_queue
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];
}
通過上面的源碼可以看到_dispatch_get_root_queue方法的傳值,qos為4,overcommit為0,1,串行為1,并發(fā)為0,默認為1。
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");
}
}
這里其實是return _dispatch_root_queues[2 * (qos - 1) + overcommit]
也就是說target queue就是從_dispatch_root_queues隊列里面拿第(2 * (qos - 1) + overcommit)個queue。
我們接下來看下_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,
),
};
這里就拿到了上面的打印結果。
打印
NSLog(@"%@",dispatch_get_main_queue());
NSLog(@"%@",dispatch_get_global_queue(0, 0));
輸出結果為
2020-08-27 20:38:34.511876+0800 001---函數(shù)與隊列[96868:2126481] <OS_dispatch_queue_main: com.apple.main-thread>
2020-08-27 20:38:34.512160+0800 001---函數(shù)與隊列[96868:2126481] <OS_dispatch_queue_global: com.apple.root.default-qos>
(lldb) po dispatch_get_global_queue(0, 0)
<OS_dispatch_queue_global: com.apple.root.default-qos[0x109113f00] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>
dispatch_get_main_queue()組隊列可以直接輸出,是個全局靜態(tài)結構體,源碼搜索com.apple.main-thread,發(fā)現(xiàn)_dispatch_main_q如下,dq_serialnum為1是串行隊列
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_GLOBAL_OBJECT_HEADER,搜下看相當于這四句代碼
#if OS_OBJECT_HAVE_OBJC1
#define DISPATCH_GLOBAL_OBJECT_HEADER(name) \
.do_vtable = DISPATCH_VTABLE(name), \
._objc_isa = DISPATCH_OBJC_CLASS(name), \
.do_ref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT, \
.do_xref_cnt = DISPATCH_OBJECT_GLOBAL_REFCNT
#else
#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
#endif
繼續(xù)往下分析,打印dispatch_get_global_queue(0, 0)發(fā)現(xiàn)它的width = 0xfff,也就是0x1000減1,給了全局并發(fā)隊列
// dispatch_init
// _dispatch_root_queues init 初始化就是0xfff,為了區(qū)分自定義的,自定義的是0xffe,任何隊列都是由_dispatch_root_queues進行模板創(chuàng)建的,除去main_queue。
// width = 0xfff
// 自定義: 0xffe
總結一下各種queue的獲取方式吧:
自己create創(chuàng)建的queue是需要alloc分配內存以后init,最后從root_queue里面的拿一個作為新queue的target queue的
main和global queue是不需要alloc init的,直接從root_queue里拿出對應的queue即可