[TOC]
GCD 简介
- 什么是GCD?
全称是 Grand Central Dispatch
- 纯
C
语言,提供了非常多强大的函数 GCD的优势 -
GCD
是苹果公司为多核的并行运算提出的解决方案 -
GCD
会自动利用更多的CPU
内核(比如双核、四核) -
GCD
会自动管理线程的生命周期(创建线程、调度任务、销毁线程) 程序员只需要告诉GCD
想要执行什么任务,不需要编写任何线程管理代码
函数
将任务添加到队列,并且指定执行任务的函数
任务使用 block
封装
- 任务的
block
没有参数也没有返回值 - 执行任务的函数
异步 dispatch_async
- 不用等待当前语句执行完毕,就可以执行下一条语句 * 会开启线程执行
block
的任务 - 异步是多线程的代名词
同步 dispatch_sync
- 必须等待当前语句执行完毕,才会执行下一条语
句 - 不会开启线程
- 在当前执行
block
的任务
外部block块 内部调用
队列
f0a09ae0e5400f93f6dd0cbc20cd6663afb29b47ad6ab1e3de0826038e11a2aa
队列和函数
140abcf0229f21455a45870eafd385e3死锁
aa0e28c8974181fa4abbf3ac8d731819相关案例
- 案例一
a8caecc8c1918a37dffe8885e3ea7c45互相等待
- 案例二
ba739c2f513c45ba49770b36c9a4b0db互相等待
- 案例三
主线程内添加同步串行队列,互相等待堵塞线程
int main(int argc, const char * argv[]) {
@autoreleasepool {
dispatch_sync(dispatch_get_main_queue(), ^(void){
NSLog(@"这里死锁了");
});
}
return 0;
}
案例四:
dsipatch_apply嵌套使用也会死锁.
dispatch_queue_t queue = dispatch_queue_create("me.tutuge.test.gcd", DISPATCH_QUEUE_SERIAL);
dispatch_apply(3, queue, ^(size_t i) {
NSLog(@"apply loop: %zu", i);
//再来一个dispatch_apply!死锁!
dispatch_apply(3, queue, ^(size_t j) {
NSLog(@"apply loop inside %zu", j);
});
});
判断是否发生死锁的最好方法就是看有没有在串行队列
(当然也包括主队列
)中向这个队列添加任务。
我们使用
同步的方法编程
,往往是要求保证任务之间的执行顺序是完全确定的。且不说GCD
提供了很多强大的功能来满足这个需求,向串行队列
中同步的添加任务
本身就是不合理的,毕竟队列已经是串行
的了,直接异步添加
就可以了.
底层探究
串行队列和并发队列创建
b944754d80770b7a69e50d833e10114a发现
target
和width
的值是不一样的.
队列是如果创建的
- 首先在
libdispatch
源码中找到dispatch_queue_create
的创建方式
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
跟进去查看
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集合,dqai里面会有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;
…… //设置QOS
if (tq && dx_type(tq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE) {
…… //tq为NULL所以不执行这段
} else if (tq && !tq->do_targetq) {
…… //tq为NULL所以不执行这段
} else {
if (overcommit == _dispatch_queue_attr_overcommit_unspecified) {
// 串行queue默认overcommit,并行queue默认不overcommit
overcommit = dqai.dqai_concurrent ?
_dispatch_queue_attr_overcommit_disabled :
_dispatch_queue_attr_overcommit_enabled;
}
}
// 第一个参数 qos 为 4
//第二个参数 overcommit 并发为0,串行为1
if (!tq) {
tq = _dispatch_get_root_queue(
qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos,
overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;//串行1 并发0
if (unlikely(!tq)) {
DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute");
}
}
// Step 2: Initialize the queue
//如果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) {
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
vtable = DISPATCH_VTABLE(queue_serial);
}
//设置autorelease_frequency以及如果label是muteable的转换为immutable
……
// 开辟内存 - 生成响应的对象 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));
// 设置label,priority,target queue
dq->dq_label = label;
//优先级
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;
区分串行和并发
if (dqai.dqai_concurrent) {
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
vtable = DISPATCH_VTABLE(queue_serial);
}
dispatch_queue_attr_info_t
分析
1.首先,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;
- _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 = { };
// dqa如果是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);
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_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 = -(int)(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;
}
看完这些,我们回到上面的_dispatch_lane_create_with_target
代码去接着分析
首先创建了一个空的结构体dqai
,下面就直接判断参数dqa
,
-
如果是空,就直接返回,否则就往下走。通过代码走向,可以知道,其实这个参数,就是
dispatch_queue_create()
的第二个参数,串行传NULL
,并发传的是非NULL
。 -
意味着如果是串行,
dqai.dqai_concurrent
就是为空,再回过头看一下,底层就是通过dqai.dqai_concurrent
来区分并发和串行的。 -
串行队列传的是NULL ,所以直接返回.
-
并行队列,通过按位取余设置下面的各个参数
两种队列通过
dqai.dqai_concurrent
区分
_dispatch_get_root_queue分析
_dispatch_root_queues方法定义:从数组中取出下表为6/7的地址
_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];
}
- _dispatch_root_queues
根据下标去对应
dispatch_queue_global_s
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,
),
};
这里其实是return _dispatch_root_queues[2 * (qos - 1) + overcommit]
也就是说target queue
就是从_dispatch_root_queues
队列里面拿第(2 * (qos - 1) + overcommit)个queue
,由于QOS
最大为6
,并且还有over commit
的区分.
注意串行queue
默认是overcommit
的为1
,并行是不overcommit
的为0
。
typedef enum {
_dispatch_queue_attr_overcommit_unspecified = 0,
_dispatch_queue_attr_overcommit_enabled,
_dispatch_queue_attr_overcommit_disabled,
} _dispatch_queue_attr_overcommit_t;
-
qos
的枚举值
#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)
创建target queue
_dispatch_lane_create_with_target
有如下代码
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);
}
//设置autorelease_frequency以及如果label是muteable的转换为immutable
……
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));
- 首先通过了
dqai.dqai_concurrent
来设置了vtable
通过各种宏可以知道其实并行queue
的vtable
就是OS_dispatch_concurrent_class
;
串行queue
的的vtable
就是OS_dispatch_serial_class
,这也就是两种queue
对应的class
。
#define DISPATCH_VTABLE(name) DISPATCH_OBJC_CLASS(name)
#define DISPATCH_OBJC_CLASS(name) (&DISPATCH_CLASS_SYMBOL(name))
#define DISPATCH_CLASS_SYMBOL(name) OS_dispatch_##name##_class
- 通过
_dispatch_object_alloc
给vtable
类分配了内存空间,大小为dispatch_lane_s
结构体的大小
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s));
typedef struct dispatch_lane_s *dispatch_queue_serial_t;
typedef struct dispatch_lane_s *dispatch_queue_concurrent_t;
- 通过
_dispatch_queue_init
初始化queue
这一段主要是设置state
、width
之类的
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;
}
-
width
:最大并发的线程数
#define DISPATCH_QUEUE_WIDTH_MAX (DISPATCH_QUEUE_WIDTH_FULL - 2) //4094
#define DISPATCH_QUEUE_WIDTH_FULL 0x1000ull
-
initial_state
:这个queue
是不是一开始就是active
状态,如果不是的话,需要手动执行dispatch_active
以后才能激活
// inactive的initial_state_bits如下,如果是一开始就active的initial_state_bits为0
#define DISPATCH_QUEUE_INACTIVE 0x0100000000000000ull
- 设置
priority、label、target queue
- 返回
_dispatch_trace_queue_create(queue)
将队列插入到队列数组中,设置队列头尾节点等
总结
target:com.apple.root.default-qos com.apple.root.default-qos.overcommit
width: DISPATCH_QUEUE_WIDTH_FULL - 2(0xffe) 0x1000ull(0x1)
都得以验证.
我们创建串行queue
的时候是取的第2 * (qos
- 1) + overcommit
= 2 * (DISPATCH_QOS_DEFAULT
- 1) + 1 = 2 * (4 - 1) + 1 = 7个queue
,也就是"com.apple.root.default-qos.overcommit
",和上面试验创建串行queue
拿到的target queue
是一致的。下标0开始;
- 创建一个新
queue
的任务比较重要的几步主要是:
· 设置一下各种参数给dqai
· 用_dispatch_get_root_queue
创建一个target queue
· 用_dispatch_object_alloc
分配内存,并通过_dispatch_queue_init
创建一个queue
· 将各种label、qos
等设置给queue
· 调用_dispatch_trace_queue_create
返回一个queue
dispatch_get_main_queue
dispatch_queue_main_t
dispatch_get_main_queue(void)
{
return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
}
结果是个
DISPATCH_GLOBAL_OBJECT
宏,搜索一下找到
#define DISPATCH_GLOBAL_OBJECT(type, object) ((OS_OBJECT_BRIDGE type)&(object))
-
_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_get_default_queue 是一个宏定义
#define _dispatch_get_default_queue(overcommit) \
_dispatch_root_queues[DISPATCH_ROOT_QUEUE_IDX_DEFAULT_QOS + \
!!(overcommit)]._as_dq
- overcommit qos index values need bit 1 set
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,overcommit
为true,所以main_queue
拿的是_dispatch_root_queues
里面的第七
个,也就是"com.apple.root.default-qos.overcommit
",和串行queue
拿到的target queue
是一致的
dispatch_get_global_queue
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);
}
获取
global
对列的最后也是转调的_dispatch_get_root_queue
,返回_dispatch_root_queues[2 * (qos - 1) + overcommit]
,在这个场景下的QOS
为DISPATCH_QOS_DEFAULT=4
(对应priority
为0
的时候),默认overcommit
也是0
,所以拿的是第6
个queue
,也就是"com.apple.root.default-qos"
。
总结一下各种queue的获取方式吧:
- 自己
create
创建的queue
是需要alloc
分配内存以后init
,最后从root_queue
里面的拿一个作为新queue
的target queue
的 -
main
和global queue
是不需要alloc init
的,直接从root_queue
里拿出对应的queue
即可.
网友评论