GCD簡介
什么是GCD?
全稱是 Grand Central Dispatch
純 C 語言绞绒,提供了非常多強(qiáng)大的函數(shù) GCD的優(yōu)勢
GCD 是蘋果公司為多核的并行運(yùn)算提出的解決方案
GCD 會自動(dòng)利用更多的CPU內(nèi)核(比如雙核度硝、四核)
GCD 會自動(dòng)管理線程的生命周期(創(chuàng)建線程依沮、調(diào)度任務(wù)盗舰、銷毀線程) 程序員只需要告訴 GCD 想要執(zhí)行什么任務(wù),不需要編寫任何線程管理代碼
函數(shù)
將任務(wù)添加到隊(duì)列扎谎,并且指定執(zhí)行任務(wù)的函數(shù)
任務(wù)使用 block 封裝
- 任務(wù)的 block 沒有參數(shù)也沒有返回值
- 執(zhí)行任務(wù)的函數(shù)
- 異步
dispatch_async
- 不用等待當(dāng)前語句執(zhí)行完畢碳想,就可以執(zhí)行下一條語句 * 會開啟線程執(zhí)行 block 的任務(wù)
- 異步是多線程的代名詞
- 同步
dispatch_sync
- 必須等待當(dāng)前語句執(zhí)行完畢,才會執(zhí)行下一條語
句 - 不會開啟線程
- 在當(dāng)前執(zhí)行 block 的任務(wù)
隊(duì)列
隊(duì)列的創(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: 隊(duì)列的唯一標(biāo)識符毁靶,可以傳空值胧奔。
dispatch_queue_attr_t attr: 標(biāo)識隊(duì)列的類型,區(qū)分是串行隊(duì)列還是并發(fā)隊(duì)列预吆。
DISPATCH_QUEUE_SERIAL: 串行隊(duì)列
DISPATCH_QUEUE_CONCURRENT: 并發(fā)隊(duì)列
串行隊(duì)列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("serial_queue", DISPATCH_QUEUE_SERIAL);
常用的主隊(duì)列就是串行隊(duì)列龙填,dispatch_get_main_queue()
專門用在主線程調(diào)度任務(wù)的隊(duì)列,也稱UI隊(duì)列
不會再開啟線程
如果有任務(wù)執(zhí)行啡浊,再添加其他任務(wù)觅够,會被堵塞
并發(fā)隊(duì)列的創(chuàng)建方法
dispatch_queue_t queue = dispatch_queue_create("concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
常用的全局隊(duì)列就是并發(fā)隊(duì)列dispatch_get_global_queue(long identifier, unsigned long flags),它可以直接執(zhí)行異步任務(wù)巷嚣。該方法第一個(gè)參數(shù)是優(yōu)先級喘先,全局隊(duì)列的優(yōu)先級為DISPATCH_QUEUE_PRIORITY_DEFAULT,這個(gè)值是一個(gè)為0的宏廷粒,所以也可以傳0窘拯。unsigned long flags: 蘋果官方文檔的解釋是Flags that are reserved for future use。標(biāo)記這個(gè)參數(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
隊(duì)列和函數(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");
打印結(jié)果為1思喊,5,2次酌,4恨课,3,先是順序執(zhí)行岳服,異步隊(duì)列不會阻塞剂公,但是會耗時(shí),所以會慢些
例子二吊宋,選擇題
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");
});
// 堵塞 - 護(hù)犢子
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行堵塞拖吼,阻塞耗時(shí)比異步隊(duì)列耗時(shí)久鳞上,所以0在1,2绿贞,3之后運(yùn)行因块,0在主線程,7籍铁,8涡上,9在它之后開啟異步線程,耗時(shí)拒名,所以0在7吩愧,8,9之前
例子三
// 同步隊(duì)列
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");
打印結(jié)果增显,1雁佳,5,2同云,產(chǎn)生死鎖崩潰糖权,首先是一個(gè)串行隊(duì)列,1炸站,5線執(zhí)行星澳,然后執(zhí)行異步函數(shù)里的任務(wù),2旱易,同步代碼塊禁偎,4,在4這里產(chǎn)生阻塞阀坏,需要等同步代碼塊執(zhí)行完如暖,同步代碼塊里有任務(wù)3,但是串行隊(duì)列的原則是先進(jìn)先出忌堂,所以3需要等4任務(wù)執(zhí)行完后才能執(zhí)行盒至,產(chǎn)生死鎖。
如果把4任務(wù)提前會死鎖嗎
// 同步隊(duì)列
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");
打印結(jié)果 1士修,5妄迁,2,4李命,崩潰,因?yàn)槿蝿?wù)3和異步函數(shù)形成相互等待箫老,使用方面要特別注意串行隊(duì)列和同步函數(shù)封字。判斷是否發(fā)生死鎖的最好方法就是看有沒有在串行隊(duì)列(當(dāng)然也包括主隊(duì)列)中向這個(gè)隊(duì)列添加任務(wù)。
死鎖
? 主線程因?yàn)槟阃胶瘮?shù)的原因等著先執(zhí)行任務(wù)
? 主隊(duì)列等著主線程的任務(wù)執(zhí)行完畢再執(zhí)行自己的任務(wù)
? 主隊(duì)列和主線程相互等待會造成死鎖
隊(duì)列是如何創(chuàng)建的
我們通過dispatch_queue_create創(chuàng)建隊(duì)列,我們點(diǎn)進(jìn)去發(fā)現(xiàn)看不到其他的阔籽,需要配合源碼分析流妻,首先我們在dispatch_queue_create處下一個(gè)dispatch_queue_create的符號斷點(diǎn),可以看到它在libdispatch動(dòng)態(tài)庫里面笆制,在Apple open source里下載對應(yīng)的源碼绅这。
打開源碼,搜索dispatch_queue_create( 發(fā)現(xiàn)搜出來很多在辆,因?yàn)槲覀兇┑牡谝粋€(gè)參數(shù)是字符串证薇,搜索dispatch_queue_create(con,結(jié)果如下
來到這里
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);
}
再往下進(jìn)入方法_dispatch_lane_create_with_target
QOS:類似于優(yōu)先級匆篓,在創(chuàng)建global queue的時(shí)候的第一個(gè)參數(shù)就是priority或者QOS浑度。
over commit:如果當(dāng)前隊(duì)列沒有可以分配的空余線程,就開啟一個(gè)新線程來做任務(wù)
我們創(chuàng)建隊(duì)列主要是通過第二個(gè)參數(shù)區(qū)分是串行還是并行鸦概,也就是重點(diǎn)在于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 = { };
//默認(rèn)是串行隊(duì)列窗市,如果傳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;
}
第一句代碼就是將我們的外界傳進(jìn)來區(qū)分串行還是并發(fā)的參數(shù)傳進(jìn)去創(chuàng)建了一個(gè) dispatch_queue_attr_info_t 類型的結(jié)構(gòu)體先慷。
一查 dispatch_queue_attr_info_t 是一個(gè)結(jié)構(gòu)體位域,結(jié)構(gòu)體位域可以通過一些位運(yùn)算取出我們想要的內(nèi)容咨察,過濾掉我們不想要的數(shù)據(jù)论熙。
1.串行隊(duì)列傳的是NULL ,所以直接返回.
2.并行隊(duì)列,通過按位取余設(shè)置下面的各個(gè)參數(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)
{
////其實(shí)就是把a(bǔ)ttr轉(zhuǎn)化為{}字典形式的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;
}
}
// 開辟內(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;
}
通過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開辟內(nèi)存,那我們看一下dispatch_object_t的內(nèi)容二蓝。
一般通過繼承實(shí)現(xiàn)多態(tài)誉券,這里通過聯(lián)合體的方式,包含了很多類型刊愚,避免開辟太多空間踊跟,是互斥的,同一時(shí)間只能有一個(gè)有效
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;
這里我們看一個(gè)例子鸥诽。
// com.apple.root.default-qos width = 0xffe
// com.apple.root.default-qos.overcommit width = 0x1 = 1
// 隊(duì)列 - 模板 _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);
打印結(jié)果如下
2020-08-23 22:47:45.560834+0800 001---函數(shù)與隊(duì)列[95788:1954758] 來了 master
2020-08-23 22:47:45.561110+0800 001---函數(shù)與隊(duì)列[95788:1954758] <OS_dispatch_queue_main: com.apple.main-thread>
2020-08-23 22:47:45.561291+0800 001---函數(shù)與隊(duì)列[95788:1954758] <OS_dispatch_queue_global: com.apple.root.default-qos>
2020-08-23 22:47:45.561472+0800 001---函數(shù)與隊(duì)列[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}>
通過上面分析我們可以看到一個(gè)com.apple.root.default-qos商玫,width = 0xffe,為并發(fā)隊(duì)列牡借,一個(gè)com.apple.root.default-qos.overcommit拳昌,width = 0x1 = 1為串行隊(duì)列。DISPATCH_QUEUE_WIDTH_MAX是通過源碼知道是一個(gè)宏定義钠龙,等于0x1000減2炬藤,結(jié)果為0xffe御铃。中間有一個(gè)宏DISPATCH_QUEUE_WIDTH_POOL 為0x1000減一,所以這里是減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));
_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陵像,默認(rèn)為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");
}
}
這里其實(shí)是return _dispatch_root_queues[2 * (qos - 1) + overcommit]
也就是說target queue就是從_dispatch_root_queues隊(duì)列里面拿第(2 * (qos - 1) + overcommit)個(gè)queue。
我們接下來看下_dispatch_root_queues這個(gè)數(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,
),
};
這里就拿到了上面的打印結(jié)果嗓违。
打印
NSLog(@"%@",dispatch_get_main_queue());
NSLog(@"%@",dispatch_get_global_queue(0, 0));
輸出結(jié)果為
2020-08-27 20:38:34.511876+0800 001---函數(shù)與隊(duì)列[96868:2126481] <OS_dispatch_queue_main: com.apple.main-thread>
2020-08-27 20:38:34.512160+0800 001---函數(shù)與隊(duì)列[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()組隊(duì)列可以直接輸出,是個(gè)全局靜態(tài)結(jié)構(gòu)體图贸,源碼搜索com.apple.main-thread蹂季,發(fā)現(xiàn)_dispatch_main_q如下,dq_serialnum為1是串行隊(duì)列
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,
};
這里有個(gè)宏DISPATCH_GLOBAL_OBJECT_HEADER疏日,搜下看相當(dāng)于這四句代碼
#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ā)隊(duì)列
// dispatch_init
// _dispatch_root_queues init 初始化就是0xfff沟优,為了區(qū)分自定義的涕滋,自定義的是0xffe,任何隊(duì)列都是由_dispatch_root_queues進(jìn)行模板創(chuàng)建的挠阁,除去main_queue宾肺。
// width = 0xfff
// 自定義: 0xffe
總結(jié)一下各種queue的獲取方式吧:
自己create創(chuàng)建的queue是需要alloc分配內(nèi)存以后init,最后從root_queue里面的拿一個(gè)作為新queue的target queue的
main和global queue是不需要alloc init的侵俗,直接從root_queue里拿出對應(yīng)的queue即可