这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
_dispatch_object_alloc
在creat的底层源码中,申请和开辟内存使用的是这行代码:
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s));
复制代码
_dispatch_object_alloc
做了什么?从源码一窥究竟
void *
_dispatch_object_alloc(const void *vtable, size_t size)
{
#if OS_OBJECT_HAVE_OBJC1
const struct dispatch_object_vtable_s *_vtable = vtable;
dispatch_object_t dou;
dou._os_obj = _os_object_alloc_realized(_vtable->_os_obj_objc_isa, size);
dou._do->do_vtable = vtable;
return dou._do;
#else
return _os_object_alloc_realized(vtable, size);
#endif
}
复制代码
_dispatch_object_alloc
-> _os_object_alloc_realized
_os_object_t
_os_object_alloc_realized(const void *cls, size_t size)
{
dispatch_assert(size >= sizeof(struct _os_object_s));
return _os_objc_alloc(cls, size);
}
复制代码
_dispatch_object_alloc
-> _os_object_alloc_realized
-> _os_objc_alloc
果然是在开辟内存空间
GCD底层源码继承链
在研究上面的问题之前,我们继续来查看全局队列的源码
- 主队列的类型是:
dispatch_queue_main_t
- 全局队列的类型是:
dispatch_queue_global_s
由代码我们知道,不管是全局队列还是主队列都是可以使用dispatch_queue_t
来接收的
DISPATCH_DECL(dispatch_queue);
#define DISPATCH_DECL(name) OS_OBJECT_DECL_SUBCLASS(name, dispatch_object)
也就等价于 OS_OBJECT_DECL_SUBCLASS(dispatch_queue, dispatch_object)
继续点击,发现跳不进去了,所以我们需要到源码里面去看了
#define OS_OBJECT_DECL_SUBCLASS(name, super) \
OS_OBJECT_DECL_IMPL(name, NSObject, <OS_OBJECT_CLASS(super)>)
#define OS_OBJECT_DECL_SUBCLASS(name, super) DISPATCH_DECL(name)
复制代码
全局搜索了之后,定位到了这两处的宏定义,然而我们发现第二处的宏定义正是我们进来的地方,所以这次没有研究的意义了。主要看第一个等价于
OS_OBJECT_DECL_IMPL(dispatch_queue, NSObject, <OS_OBJECT_CLASS(dispatch_object)>)
#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
复制代码
等价于:
OS_OBJECT_DECL_PROTOCOL(dispatch_queue, dispatch_object)
typedef NSObject<OS_dispatch_queue)>
* OS_OBJC_INDEPENDENT_CLASS dispatch_queue_t
#define OS_OBJECT_DECL_PROTOCOL(name, ...) \
@protocol OS_OBJECT_CLASS(name) __VA_ARGS__ \
@end
复制代码
等价于:
@protocol OS_OBJECT_CLASS(dispatch_queue) dispatch_object @end
#define OS_OBJECT_CLASS(name) OS_##name
复制代码
等价于:
OS_dispatch_queue
或者还有一个更简单的:
#define DISPATCH_DECL(name) \
typedef struct name##_s : public dispatch_object_s {} *name##_t
typedef struct dispatch_queue_s: public dispatch_object_s {} *dispatch_queue_t
复制代码
所以可以得出结论:
dispatch_queue_t
底层是一个结构体dispatch_queue_s
继承于dispatch_object_s
可以类比class
,我们知道class
的底层继承关系
class
-> object_class
-> object_object
dispatch_queue_t
-> dispatch_queue_s
-> dispatch_object_s
-> _os_object_s
->dispatch_object_t
dispatch_queue_s
就跟研究类一样,可想而知我们重点研究的是dispatch_queue_s
struct dispatch_queue_s {
DISPATCH_QUEUE_CLASS_HEADER(queue, void *__dq_opaque1);
/* 32bit hole on LP64 */
} DISPATCH_ATOMIC64_ALIGN;
复制代码
继续搜索DISPATCH_QUEUE_CLASS_HEADER
#define _DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__) \
DISPATCH_OBJECT_HEADER(x); \
DISPATCH_UNION_LE(uint64_t volatile dq_state, \
dispatch_lock dq_state_lock, \
uint32_t dq_state_bits \
); \
__pointer_sized_field__
复制代码
等价于:
DISPATCH_OBJECT_HEADER(queue);
#define DISPATCH_OBJECT_HEADER(x) \
struct dispatch_object_s _as_do[0]; \
_DISPATCH_OBJECT_HEADER(x)
复制代码
最终指向了dispatch_object_s
,也刚好验证了上面的继承过程。接着继续搜索_DISPATCH_OBJECT_HEADER
#define _DISPATCH_OBJECT_HEADER(x) \
struct _os_object_s _as_os_obj[0]; \
OS_OBJECT_STRUCT_HEADER(dispatch_##x); \
struct dispatch_##x##_s *volatile do_next; \
struct dispatch_queue_s *do_targetq; \
void *do_ctxt; \
union { \
dispatch_function_t DISPATCH_FUNCTION_POINTER do_finalizer; \
void *do_introspection_ctxt; \
}
复制代码
我们发现原来在dispatch_object_s
后面还有一层,还继承了_os_object_s
继续搜索宏定义OS_OBJECT_STRUCT_HEADER
,拆了这么多的包装之后终于拿到了dispatch_queue_s
的内部结构,发现一共有3个成员变量
#define OS_OBJECT_STRUCT_HEADER(x) \
_OS_OBJECT_HEADER(\
const void *_objc_isa, \
do_ref_cnt, \
do_xref_cnt); \
const struct x##_vtable_s *do_vtable
#else
复制代码
GCD任务执行堆栈-同步
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"同步函数分析");
});
复制代码
我们来研究一下这个NSLog执行的时机,还是看源码
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);
}
复制代码
我们只需要关注work
的流向:_dispatch_sync_f
关注第二个和第三个参数:ctxt, func
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_sync_f_inline(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func, uintptr_t dc_flags)
{
if (likely(dq->dq_width == 1)) {
// 这里有ctxt和func的调用
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))) {
// // 这里有ctxt和func的调用
return _dispatch_sync_f_slow(dl, ctxt, func, 0, dl, dc_flags);
}
if (unlikely(dq->do_targetq->do_targetq)) {
// // 这里有ctxt和func的调用
return _dispatch_sync_recurse(dl, ctxt, func, dc_flags);
}
_dispatch_introspection_sync_begin(dl);
// // 这里有ctxt和func的调用
_dispatch_sync_invoke_and_complete(dl, ctxt, func DISPATCH_TRACE_ARG(
_dispatch_trace_item_sync_push_pop(dq, ctxt, func, dc_flags)));
}
复制代码
通过在项目中下符号断点可以发现调用了_dispatch_barrier_sync_f
-> _dispatch_sync_f_slow
-> _dispatch_sync_function_invoke
-> _dispatch_sync_function_invoke_inline
-> _dispatch_client_callout
static inline void
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
return f(ctxt);
}
复制代码
要验证的话很简单看项目中的堆栈或者在控制台直接bt一下就可以。
GCD任务执行堆栈-异步
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"异步函数分析");
});
复制代码
跟上面同步函数的思路一样我们到源码里面去分析:
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);
}
复制代码
异步函数的work经过一系列封装之后赋值给了qos
,定位到了这里_dispatch_continuation_async
,重点关注qos
,结果这里直接return
了,线索到了这里就断了
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)
复制代码
上面的qos在第三个参数,所以我们这里重点要研究的是dq_push(x, y, z)
直接定位到全局并发队列这里
.dq_push = _dispatch_root_queue_push,
复制代码
_dispatch_continuation_async
-> dq_push
-> _dispatch_root_queue_push
-> _dispatch_root_queue_push_inline
-> _dispatch_root_queue_poke
-> _dispatch_root_queue_poke_slow
-> _dispatch_root_queues_init
->_dispatch_root_queues_init_once
static inline void
_dispatch_root_queues_init(void)
{
dispatch_once_f(&_dispatch_root_queues_pred, NULL,
_dispatch_root_queues_init_once);
}
复制代码
定位到了单例dispatch_once_f
_dispatch_root_queues_init_once
-> _dispatch_worker_thread2
-> _dispatch_root_queue_drain
-> _dispatch_continuation_pop_inline
-> _dispatch_continuation_invoke_inline
-> _dispatch_client_callout
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
return f(ctxt); //就是一个调用执行
}
复制代码
这个异步函数过程相对比较复杂和漫长