GCD简介
GCD
全称Grand Central Dispatch,是纯 C 语言实现,提供了非常多强大的函数。主要作用是将任务添加到队列,并且指定执行任务的函数
GCD的优势
- GCD 是苹果公司为
多核的并行运算
提出的解决方案 - GCD 会自动利用更多的
CPU内核
(比如双核、四核) - GCD 会自动
管理线程的生命周期
(创建线程、调度任务、销毁线程) 程序员只需要告诉 GCD 想要执行什么任务,不需要编写任何线程管理代码
GCD基础写法
/**
* 还原最基础的写法很重要,帮助我们更好的理解GCD的作用 ->
将任务添加到队列,并且指定执行任务的函数
*/
- (void)syncTest{
// 任务块
dispatch_block_t block = ^{
NSLog(@"hello GCD");
};
//制定任务的队列 -> 串行队列
dispatch_queue_t queue = dispatch_queue_create("com.lg.cn", NULL);
// 函数
dispatch_async(queue, block);
}
函数
任务使用 block 封装,任务的 block 没有参数也没有返回值
执行任务的函数
- 异步
dispatch_async
- 不用等待当前语句执行完毕,就可以执行下一条语句
- 会开启线程执行 block 的任务
- 异步是多线程的代名词
- 同步
dispatch_sync
- 必须等待当前语句执行完毕,才会执行下一条语句
- 不会开启线程
- 在当前执行 block 的任务
队列
队列
也是一种线性表,它的特性是先进先出
(FIFO),插入在一端删除在另一端。就像排队一样,刚来的人入队(push)要排在队尾(rear),每次出队(pop)的都是队首(front)的人。
![](https://img.haomeiwen.com/i1212147/e7fdaa90721340d4.png)
![](https://img.haomeiwen.com/i1212147/652131172da0474d.png)
下面我们来分析几道面试题
- 面试题一
- (void)textDemo1 {
// 当前是一个并发队列
dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
}
// 打印结果 1 5 2 3 4
- 面试题二
- (void)textDemo2 {
// 同步队列
dispatch_queue_t queue = dispatch_queue_create("cooci", NULL);
NSLog(@"1");
// 异步函数
dispatch_async(queue, ^{
NSLog(@"2");
// 同步
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");
}
// 死锁产生崩溃
异步函数代码块
中添加了三个任务
- NSLog(@"2");
- dispatch_sync(queue, ^{
NSLog(@"3");
}); - NSLog(@"4");
queue
是一个串行队列,NSLog(@"3");
是在任务NSLog(@"4");
之后
同步函数代码块
会堵塞NSLog(@"4");
执行,
NSLog(@"3");
会堵塞同步函数代码块会
执行,
NSLog(@"4");
又会堵塞NSLog(@"3");
执行,最终形成死锁
删除NSLog(@"4");
代码,还会产生死锁吗?
- (void)textDemo2 {
// 同步队列
dispatch_queue_t queue = dispatch_queue_create("cooci", NULL);
NSLog(@"1");
// 异步函数
dispatch_async(queue, ^{
NSLog(@"2");
// 同步
dispatch_sync(queue, ^{
NSLog(@"3");
});
});
NSLog(@"5");
}
// 运行产生死锁崩溃
异步函数代码块
中添加了两个任务
- NSLog(@"2");
- dispatch_sync(queue, ^{
NSLog(@"3");
});
同步函数代码块
会堵塞异步函数代码块
执行,
NSLog(@"3");
会堵塞同步函数代码块
会执行,
异步函数代码块
又会堵·NSLog(@"3");
执行,最终形成死锁
最终本质是同步函数代码块
与异步函数代码块
产生堵塞,形成死锁
。
- 面试题三
- (void)wbinterDemo{
// 串行队列
dispatch_queue_t queue = dispatch_queue_create("com.lg.cooci.cn", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
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
答案是 A
。
分析: 串行队列
相当于把异步变成同步
按顺序执行,保证FIFO。异步函数串行队列:开启一条新线程 任务一个接着一个
- (void)wbinterDemo{
// 并发队列
dispatch_queue_t queue = dispatch_queue_create("com.demo.test", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
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
答案是 A C
。
分析: 同步函数代码块中NSLog(@"3");
一定会堵塞NSLog(@"0");
以下的代码,所以3
一定在0
之前,0
肯定在7 8 9
之前。并发队列
中1 2 3
之间没有先后顺序,7 8 9
之间也没有先后顺序,最终满足条件的是A C
。
注意: 同步函数
只堵塞下面的代码,所以1 2 3
没有先后顺序
主队列分析
队列一共有四种串行队列
、并发队列
、主队列
、全局并发队列
主队列
- 专⻔用来在
主线程上
调度任务的串行队列
- 不会开启线程
- 如果当前主线程正在有任务执行,那么无论主队列中当前被添加了什么任务,都不会被调度
dispatch_get_main_queue()
;
全局并发队列
- 为了方便程序员的使用,苹果提供了全局队列
dispatch_get_global_queue(0, 0)
- 全局队列是一个
并发队列
- 在使用多线程开发时,如果对队列没有特殊需求,在执行异步任务时,可以直接使用
全局队列
串行队列:dispatch_queue_t serial = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
并发队列:dispatch_queue_t conque = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
主队列:dispatch_queue_t mainQueue = dispatch_get_main_queue();
全局队列:dispatch_queue_t globQueue =dispatch_get_global_queue(0, 0);
主队列会在main
函数之前创建
![](https://img.haomeiwen.com/i1212147/283fab8363e5817d.png)
主队列分析
方式一
- 通过
bt
打印分析
![](https://img.haomeiwen.com/i1212147/e4477e218d58fb27.png)
- 下载libdispatch源码搜索
dispatch_get_main_queue
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) ((type)&(object))
- 全局搜索
_dispatch_main_q
// 6618342 Contact the team that owns the Instrument DTrace probe before
// renaming this symbol
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,
};
方式二
-
通过bt打印
主队列
找到名称
截屏2021-09-11 下午4.19.00.png
-
全局搜索
com.apple.main-thread
image.png
由.dq_atomic_flags = DQF_WIDTH(1),
,.dq_serialnum = 1
可知是串行队列
。下面我们分析为什么.dq_atomic_flags = DQF_WIDTH(1)
就是串行队列?
串行和并发的底层源码
-
串行队列
和并行队列
都是通过dispatch_queue_create
创建的,下面我们在源码中搜索
![](https://img.haomeiwen.com/i1212147/2cbb1e8eeec5abf1.png)
- 进入
_dispatch_lane_create_with_target
,看该方法的返回值
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)
{
// 面向对象封装
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
// 优先级相关的处理
// Step 1: Normalize arguments (qos, overcommit, tq)
//
// 省略代码
......
//
// Step 2: Initialize the queue
//
// 因为dq是返回值,这里主要查看dq是如何创建的
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s));
// 如果是并发队列返回DISPATCH_QUEUE_WIDTH_MAX,否则返回1
_dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
(dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
// 省略代码
......
return _dispatch_trace_queue_create(dq)._dq;
}
- 进入
_dispatch_queue_init
查看传值dqai_concurrent ?DISPATCH_QUEUE_WIDTH_MAX : 1
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;
}
得出结论
DQF_WIDTH = 1
就为串行队列
,跟dq_serialnum=1
没有关系
dq_serialnum
中的_dispatch_queue_serial_numbers
只是一个标识,下面进行分析
- 全局搜索
_dispatch_queue_serial_numbers
unsigned long volatile _dispatch_queue_serial_numbers =
DISPATCH_QUEUE_SERIAL_NUMBER_INIT;
// 全局搜索DISPATCH_QUEUE_SERIAL_NUMBER_INIT
// skip zero
// 1 - main_q -> NUMBER为1就是主队列
// 2 - mgr_q
// 3 - mgr_root_q
// 4,5,6,7,8,9,10,11,12,13,14,15 - global queues
// 17 - workloop_fallback_q
// we use 'xadd' on Intel, so the initial value == next assigned
#define DISPATCH_QUEUE_SERIAL_NUMBER_INIT 17
- 全局搜索查看
os_atomic_inc_orig
方法
#define os_atomic_inc_orig(p, m) \
os_atomic_add_orig((p), 1, m)
#define os_atomic_add_orig(p, v, m) \
_os_atomic_c11_op_orig((p), (v), m, add, +)
#define _os_atomic_c11_op_orig(p, v, m, o, op) \
atomic_fetch_##o##_explicit(_os_atomic_c11_atomic(p), v, \
memory_order_##m)
- 最终演变为
atomic_fetch_add_explicit
函数
_dispatch_lane_create_with_target
中有一个面向对象封装的方法
_dispatch_queue_attr_to_info
,下面进行查看
- 串行队列传
NULL
的原因,就是当dqai
为NULL
时,直接返回dqai
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]) {
#ifndef __APPLE__
if (memcmp(dqa, &_dispatch_queue_attrs[0],
sizeof(struct dispatch_queue_attr_s)) == 0) {
dqa = (dispatch_queue_attr_t)&_dispatch_queue_attrs[0];
} else
#endif // __APPLE__
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_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;
}
GCD底层源码继承链
下面来分析全局并发队列
![](https://img.haomeiwen.com/i1212147/d39b9f0212fa41d2.png)
-
全局搜索
com.apple.root.default-qos
image.png
-
由于队列创建返回的都是
dispatch_queue_t
类型,就从这里入手开始探索
DISPATCH_DECL(dispatch_queue);
#define DISPATCH_DECL(name) OS_OBJECT_DECL_SUBCLASS(name, dispatch_object)
- 源码中搜索
OS_OBJECT_DECL_SUBCLASS
#define OS_OBJECT_DECL_SUBCLASS(name, super) \
OS_OBJECT_DECL_IMPL(name, NSObject, <OS_OBJECT_CLASS(super)>)
#define OS_OBJECT_DECL_IMPL(name, adhere, ...) \
OS_OBJECT_DECL_PROTOCOL(name, __VA_ARGS__) \
typedef adhere<OS_OBJECT_CLASS(name)> \
* OS_OBJC_INDEPENDENT_CLASS name##_t
#define OS_OBJECT_DECL_PROTOCOL(name, ...) \
@protocol OS_OBJECT_CLASS(name) __VA_ARGS__ \
@end
// 拼接一个_vtable
#define OS_OBJECT_CLASS_SYMBOL(name) _##name##_vtable
-
DISPATCH_DECL
在源码中对应
#define DISPATCH_DECL(name) \
typedef struct name##_s : public dispatch_object_s {} *name##_t
// 都是dispatch_object_t类型
#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_channel_s *_dch;
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;
#endif // !__DISPATCH_BUILDING_DISPATCH__
DISPATCH_DECL(dispatch_queue);
typedef struct dispatch_queue_s : public dispatch_object_s {} *dispatch_queue_t
相当于dispatch_queue_t->dispatch_queue_s->dispatch_object_s->_os_object_s->dispatch_object_t
class->objc_class{ isa superclass } ->objc_object
最终的继承链关系dispatch_queue_t->dispatch_queue_s->dispatch_object_s->_os_object_s->dispatch_object_t
MT和KS面试题
面试题一
// 声明属性num
@interface ViewController ()
@property (atomic, assign) int num;
@end
// 美团面试题
- (void)MTDemo{
while (self.num < 5) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.num++;
});
}
NSLog(@"end : %d",self.num);
}
结果:最终num
的值大于等于5
分析: 因为是异步函数
,当num<5
的时候,至少会开辟5个以上的线程
,最终num++
结果大于等于5
面试题二
// 快手面试题
- (void)KSDemo{
for (int i= 0; i<10000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.num++;
});
}
NSLog(@"end : %d",self.num);
}
结果:最终num
的值小于等于10000
分析: 因为是异步函数
而for循环只执行1000次
。当for循环执行结束的时候,有可能一些异步函数还没有执行完成
,这个时候num值必然小于等于10000
GCD的任务执行堆栈(同步)
dispatch_sync
的block()
在什么时候执行? 全局搜索dispatch_sync(dis
源码如下
DISPATCH_NOINLINE
void
dispatch_sync(dispatch_queue_t dq, dispatch_block_t work)
{
uintptr_t dc_flags = DC_FLAG_BLOCK;
if (unlikely(_dispatch_block_has_private_data(work))) {
return _dispatch_sync_block_with_privdata(dq, work, dc_flags);
}
_dispatch_sync_f(dq, work, _dispatch_Block_invoke(work), dc_flags);
}
#endif // __BLOCKS__
- 查看传入的参数
work
去了哪里?这里查看_dispatch_Block_invoke
方法
#define _dispatch_Block_invoke(bb) \
((dispatch_function_t)((struct Block_layout *)bb)->invoke)
- 查看
_dispatch_sync_f
DISPATCH_NOINLINE
static void
_dispatch_sync_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func,
uintptr_t dc_flags)
{
_dispatch_sync_f_inline(dq, ctxt, func, dc_flags);
}
- 查看
_dispatch_sync_f_inline
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_sync_f_inline(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func, uintptr_t dc_flags)
{
if (likely(dq->dq_width == 1)) {
return _dispatch_barrier_sync_f(dq, ctxt, func, dc_flags);
}
if (unlikely(dx_metatype(dq) != _DISPATCH_LANE_TYPE)) {
DISPATCH_CLIENT_CRASH(0, "Queue type doesn't support dispatch_sync");
}
dispatch_lane_t dl = upcast(dq)._dl;
// Global concurrent queues and queues bound to non-dispatch threads
// always fall into the slow case, see DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE
if (unlikely(!_dispatch_queue_try_reserve_sync_width(dl))) {
return _dispatch_sync_f_slow(dl, ctxt, func, 0, dl, dc_flags);
}
if (unlikely(dq->do_targetq->do_targetq)) {
return _dispatch_sync_recurse(dl, ctxt, func, dc_flags);
}
_dispatch_introspection_sync_begin(dl);
_dispatch_sync_invoke_and_complete(dl, ctxt, func DISPATCH_TRACE_ARG(
_dispatch_trace_item_sync_push_pop(dq, ctxt, func, dc_flags)));
}
- 加一个符号断点
_dispatch_sync_f_slow
发现进入了
image.png
DISPATCH_NOINLINE
static void
_dispatch_sync_f_slow(dispatch_queue_class_t top_dqu, void *ctxt,
dispatch_function_t func, uintptr_t top_dc_flags,
dispatch_queue_class_t dqu, uintptr_t dc_flags)
{
dispatch_queue_t top_dq = top_dqu._dq;
dispatch_queue_t dq = dqu._dq;
if (unlikely(!dq->do_targetq)) {
return _dispatch_sync_function_invoke(dq, ctxt, func);
}
pthread_priority_t pp = _dispatch_get_priority();
struct dispatch_sync_context_s dsc = {
.dc_flags = DC_FLAG_SYNC_WAITER | dc_flags,
.dc_func = _dispatch_async_and_wait_invoke,
.dc_ctxt = &dsc,
.dc_other = top_dq,
.dc_priority = pp | _PTHREAD_PRIORITY_ENFORCE_FLAG,
.dc_voucher = _voucher_get(),
.dsc_func = func,
.dsc_ctxt = ctxt,
.dsc_waiter = _dispatch_tid_self(),
};
_dispatch_trace_item_push(top_dq, &dsc);
__DISPATCH_WAIT_FOR_QUEUE__(&dsc, dq);
if (dsc.dsc_func == NULL) {
// dsc_func being cleared means that the block ran on another thread ie.
// case (2) as listed in _dispatch_async_and_wait_f_slow.
dispatch_queue_t stop_dq = dsc.dc_other;
return _dispatch_sync_complete_recurse(top_dq, stop_dq, top_dc_flags);
}
_dispatch_introspection_sync_begin(top_dq);
_dispatch_trace_item_pop(top_dq, &dsc);
_dispatch_sync_invoke_and_complete_recurse(top_dq, ctxt, func,top_dc_flags
DISPATCH_TRACE_ARG(&dsc));
}
- 继续添加
符号断点
发现执行了_dispatch_sync_function_invoke
方法
DISPATCH_NOINLINE
static void
_dispatch_sync_function_invoke(dispatch_queue_class_t dq, void *ctxt,
dispatch_function_t func)
{
_dispatch_sync_function_invoke_inline(dq, ctxt, func);
}
- 查看
_dispatch_sync_function_invoke_inline
方法
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_sync_function_invoke_inline(dispatch_queue_class_t dq, void *ctxt,
dispatch_function_t func)
{
dispatch_thread_frame_s dtf;
_dispatch_thread_frame_push(&dtf, dq);
_dispatch_client_callout(ctxt, func);
_dispatch_perfmon_workitem_inc();
_dispatch_thread_frame_pop(&dtf);
}
- 查看
_dispatch_client_callout
方法
#undef _dispatch_client_callout
void
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
@try {
return f(ctxt);
}
@catch (...) {
objc_terminate();
}
}
- 断点
bt
验证探索流程
image.png
GCD的任务执行堆栈(异步)
dispatch_async
的block()
在什么时候执行?全局搜索dispatch_async(dis源码如下
#ifdef __BLOCKS__
void
dispatch_async(dispatch_queue_t dq, dispatch_block_t work)
{
dispatch_continuation_t dc = _dispatch_continuation_alloc();
uintptr_t dc_flags = DC_FLAG_CONSUME;
dispatch_qos_t qos;
qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);
_dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}
#endif
- 查看
_dispatch_continuation_init
方法
DISPATCH_ALWAYS_INLINE
static inline dispatch_qos_t
_dispatch_continuation_init(dispatch_continuation_t dc,
dispatch_queue_class_t dqu, dispatch_block_t work,
dispatch_block_flags_t flags, uintptr_t dc_flags)
{
void *ctxt = _dispatch_Block_copy(work);
dc_flags |= DC_FLAG_BLOCK | DC_FLAG_ALLOCATED;
if (unlikely(_dispatch_block_has_private_data(work))) {
dc->dc_flags = dc_flags;
dc->dc_ctxt = ctxt;
// will initialize all fields but requires dc_flags & dc_ctxt to be set
return _dispatch_continuation_init_slow(dc, dqu, flags);
}
dispatch_function_t func = _dispatch_Block_invoke(work);
if (dc_flags & DC_FLAG_CONSUME) {
func = _dispatch_call_block_and_release;
}
return _dispatch_continuation_init_f(dc, dqu, ctxt, func, flags, dc_flags);
}
- 查看
_dispatch_continuation_init_f
方法 - 查看
_dispatch_continuation_priority_set
优先级异步处理
DISPATCH_ALWAYS_INLINE
static inline dispatch_qos_t
_dispatch_continuation_priority_set(dispatch_continuation_t dc,
dispatch_queue_class_t dqu,
pthread_priority_t pp, dispatch_block_flags_t flags)
{
dispatch_qos_t qos = DISPATCH_QOS_UNSPECIFIED;
#if HAVE_PTHREAD_WORKQUEUE_QOS
dispatch_queue_t dq = dqu._dq;
if (likely(pp)) {
bool enforce = (flags & DISPATCH_BLOCK_ENFORCE_QOS_CLASS);
bool is_floor = (dq->dq_priority & DISPATCH_PRIORITY_FLAG_FLOOR);
bool dq_has_qos = (dq->dq_priority & DISPATCH_PRIORITY_REQUESTED_MASK);
if (enforce) {
pp |= _PTHREAD_PRIORITY_ENFORCE_FLAG;
qos = _dispatch_qos_from_pp_unsafe(pp);
} else if (!is_floor && dq_has_qos) {
pp = 0;
} else {
qos = _dispatch_qos_from_pp_unsafe(pp);
}
}
dc->dc_priority = pp;
#else
(void)dc; (void)dqu; (void)pp; (void)flags;
#endif
return qos;
}
查看_dispatch_continuation_async
方法
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_continuation_async(dispatch_queue_class_t dqu,
dispatch_continuation_t dc, dispatch_qos_t qos, uintptr_t dc_flags)
{
#if DISPATCH_INTROSPECTION
if (!(dc_flags & DC_FLAG_NO_INTROSPECTION)) {
_dispatch_trace_item_push(dqu, dc);
}
#else
(void)dc_flags;
#endif
return dx_push(dqu._dq, dc, qos);
}
- 查看
dx_push
#define dx_push(x, y, z) dx_vtable(x)->dq_push(x, y, z)
-
查看
dq_push
queue_global
队列
image.png
-
查看
_dispatch_root_queue_push
方法 -
查看
_dispatch_root_queue_push_inline
,因为_dispatch_root_queue_push
最终会执行到_dispatch_root_queue_push
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_root_queue_push_inline(dispatch_queue_global_t dq,
dispatch_object_t _head, dispatch_object_t _tail, int n)
{
struct dispatch_object_s *hd = _head._do, *tl = _tail._do;
if (unlikely(os_mpsc_push_list(os_mpsc(dq, dq_items), hd, tl, do_next))) {
return _dispatch_root_queue_poke(dq, n, 0);
}
}
- 查看
_dispatch_root_queue_poke
方法 - 查看
_dispatch_root_queue_poke_slow
方法
DISPATCH_NOINLINE
static void
_dispatch_root_queue_poke_slow(dispatch_queue_global_t dq, int n, int floor)
{
int remaining = n;
#if !defined(_WIN32)
int r = ENOSYS;
#endif
_dispatch_root_queues_init();
_dispatch_debug_root_queue(dq, __func__);
_dispatch_trace_runtime_event(worker_request, dq, (uint64_t)n);
...... //省略代码
-
查看
_dispatch_root_queues_init
方法
image.png
-
查看
_dispatch_root_queues_init_once
方法,打印堆栈查看到调用的_dispatch_worker_thread2
image.png
-
查看
_dispatch_worker_thread2
方法
#if !DISPATCH_USE_INTERNAL_WORKQUEUE
static void
_dispatch_worker_thread2(pthread_priority_t pp)
{
bool overcommit = pp & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG;
dispatch_queue_global_t dq;
pp &= _PTHREAD_PRIORITY_OVERCOMMIT_FLAG | ~_PTHREAD_PRIORITY_FLAGS_MASK;
_dispatch_thread_setspecific(dispatch_priority_key, (void *)(uintptr_t)pp);
dq = _dispatch_get_root_queue(_dispatch_qos_from_pp(pp), overcommit);
_dispatch_introspection_thread_add();
_dispatch_trace_runtime_event(worker_unpark, dq, 0);
int pending = os_atomic_dec2o(dq, dgq_pending, relaxed);
dispatch_assert(pending >= 0);
_dispatch_root_queue_drain(dq, dq->dq_priority,
DISPATCH_INVOKE_WORKER_DRAIN | DISPATCH_INVOKE_REDIRECTING_DRAIN);
_dispatch_voucher_debug("root queue clear", NULL);
_dispatch_reset_voucher(NULL, DISPATCH_THREAD_PARK);
_dispatch_trace_runtime_event(worker_park, NULL, 0);
}
#endif // !DISPATCH_USE_INTERNAL_WORKQUEUE
- 查看
_dispatch_root_queue_drain
方法 - 查看
_dispatch_continuation_pop_inline
方法
DISPATCH_ALWAYS_INLINE_NDEBUG
static inline void
_dispatch_continuation_pop_inline(dispatch_object_t dou,
dispatch_invoke_context_t dic, dispatch_invoke_flags_t flags,
dispatch_queue_class_t dqu)
{
dispatch_pthread_root_queue_observer_hooks_t observer_hooks =
_dispatch_get_pthread_root_queue_observer_hooks();
if (observer_hooks) observer_hooks->queue_will_execute(dqu._dq);
flags &= _DISPATCH_INVOKE_PROPAGATE_MASK;
if (_dispatch_object_has_vtable(dou)) {
dx_invoke(dou._dq, dic, flags);
} else {
_dispatch_continuation_invoke_inline(dou, flags, dqu);
}
if (observer_hooks) observer_hooks->queue_did_execute(dqu._dq);
}
- 查看
_dispatch_continuation_invoke_inline
方法 - 查看
_dispatch_client_callout
方法
// 实质上是一个调用执行
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
return f(ctxt);
}
网友评论