dispatch_async 详解
dispatch_async 详解
说明
作用:在调度队列上提交异步执行的块,并立即返回。
函数原型:
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
参数:
- queue:提交块的队列。系统保留队列,直到块运行完成。此参数不能为空。
- block:要提交给目标调度队列的块。此函数代表调用者执行Block_copy和Block_release。此参数不能为空。
此函数是将块提交到调度队列的基本机制。对此函数的调用总是在提交块后立即返回,并且从不等待调用块。目标队列确定该块是相对于提交给同一队列的其他块串行调用还是并发调用。独立的串行队列相互同时处理。
dispatch_async 函数会立即返回,block会在后台异步执行。
源码分析
void dispatch_async(dispatch_queue_t dq, void (^work)(void))
{
dispatch_async_f(dq, _dispatch_Block_copy(work),
_dispatch_call_block_and_release);
}
// 调用了下面的方法
void dispatch_async_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func)
{
//1、定义一个封装的block操作
dispatch_continuation_t dc;
// No fastpath/slowpath hint because we simply don't know
//2、dq_width == 1表示串行,就是main queue和用户创建的串行queue
if (dq->dq_width == 1) {
return dispatch_barrier_async_f(dq, ctxt, func);
}
//如果是global queue和用户创建的并行queue则继续向下走
//3、线程中有个dispatch_continuation_t缓存链表,如果获取到就把链表的下一个设为缓存,相当于把第一个取出来了
dc = fastpath(_dispatch_continuation_alloc_cacheonly());
if (!dc) {
//4、如果没有dispatch_continuation_t缓存在堆上创建一个,并且初始化后调用_dispatch_queue_push
return _dispatch_async_f_slow(dq, ctxt, func);
}
//5、初始化dispatch_continuation_t,把block封装成dispatch_continuation_t
dc->do_vtable = (void *)DISPATCH_OBJ_ASYNC_BIT;
dc->dc_func = func;
dc->dc_ctxt = ctxt;
// No fastpath/slowpath hint because we simply don't know
//6、如果do_targetq存在,则任务有do_targetq来执行
if (dq->do_targetq) {
return _dispatch_async_f2(dq, dc);
}
//7、把dispatch_continuation_t放到queue的执行列表中
_dispatch_queue_push(dq, dc);
}
//dispatch_continuation_t的结构,封装的一个block操作
struct dispatch_continuation_s {
const void *do_vtable;
struct dispatch_continuation_s *volatile do_next;
dispatch_function_t dc_func;
void *dc_ctxt
dispatch_group_t dc_group;
void *dc_data[3];
};
通过上面的方法我们可以看出,dispatch_async_f 最终将 block 封装成 dispatch_continuation_s 并调用 _dispatch_queue_push 放到对应的 queue 的执行链表结尾,global queue 是放到自己的执行链表执行,main queue 和 user queue 放到 do_targetq 的执行链表执行。
dispatch_async(dispatch_get_main_queue(), ^{})
dispatch_async(异步)和 dispatch_sync(同步)决定有没有开子线程的能力,而不是指会不会开子线程。queue 决定有没有并发的能力。开子线程我就并发,不开就串行。
所以 dispatch_async(dispatch_get_main_queue(), ^{}) 的意思是异步地在主线程按顺序执行,没有开子线程的能力。