iOS看源码:GCD(一)
GCD队列的创建
dispatch_queue_t queue1 = dispatch_queue_create("ZFD1", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t queue2 = dispatch_queue_create("ZFD2", NULL);
通过符号断点"dispatch_queue_create"可看到函数实在libdispatch.dylib中 GCD已经开源 libdispatch源码
来到GCD源码 队列创建指向了
_dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
dispatch_queue_t tq, bool legacy)
{…}
创建队列时 指定队列类型 是通过dispatch_queue_attr_t dqa这个参数来区分的。
函数内部唯一使用dqa参数的地方就是第一行的
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
明显 _dispatch_queue_attr_to_info()就是队列信息的来源
下面看看dispatch_queue_attr_info_t dqai是什么
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;
感觉很熟悉 是不是很像isa_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 = { };
//串行队列直接return
if (!dqa) return dqai;
//并发队列
...初始赋值操作
return dqai;
}
可以看到 默认的串行队列返回的dqai里面什么也没有 而并发队列则有一系列的位域的操作。
回到_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);
...
}
其中 tq 是默认带来的参数 DISPATCH_TARGET_QUEUE_DEFAULT 定义就是 NULL
这个函数最后返回的是
return _dispatch_trace_queue_create(dq)._dq;
返回结果肯定是一个dispatch_queue_t类型
往前推 那么队列的创建应该就是和dq有关
_dispatch_trace_queue_create(dq)返回的是一个dispatch_queue_class_t类型
typedef union {
struct dispatch_queue_s *_dq;
struct dispatch_workloop_s *_dwl;
struct dispatch_lane_s *_dl;
struct dispatch_queue_static_s *_dsq;
struct dispatch_queue_global_s *_dgq;
struct dispatch_queue_pthread_root_s *_dpq;
struct dispatch_source_s *_ds;
struct dispatch_mach_s *_dm;
dispatch_lane_class_t _dlu;
#ifdef __OBJC__
id<OS_dispatch_queue> _objc_dq;
#endif
} dispatch_queue_class_t
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));
dq->do_targetq = tq;
return _dispatch_trace_queue_create(dq)._dq;
typedef struct dispatch_lane_s {
DISPATCH_LANE_CLASS_HEADER(lane);
/* 32bit hole on LP64 */
} DISPATCH_ATOMIC64_ALIGN *dispatch_lane_t;
struct dispatch_queue_s {
DISPATCH_QUEUE_CLASS_HEADER(queue, void *__dq_opaque1);
/* 32bit hole on LP64 */
} DISPATCH_ATOMIC64_ALIGN;
dq.do_targetq = tq;
tq的获取:
tq = _dispatch_get_root_queue(
qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos,
overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq;
_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];
}
struct dispatch_queue_global_s _dispatch_root_queues[]
tq队列是从全局静态数组中通过qos和overcommit来获取的。
_dispatch_root_queues的初始化实在dispatch_init()时初始化创建的
libdispatcdispatch_queue_createh_init()->_dispatch_introspection_init->_dispatch_trace_queue_create(&_dispatch_root_queues[i]);
_dispatch_trace_queue_create(&_dispatch_main_q); _dispatch_trace_queue_create(&_dispatch_mgr_q);
主队列和全局队列也是在这个时候创建的
死锁
GCD的同步函数
dispatch_sync(dispatch_queue_t dq, dispatch_block_t work)
{
uintptr_t dc_flags = DC_FLAG_BLOCK;
...
_dispatch_sync_f(dq, work, _dispatch_Block_invoke(work), dc_flags);
}
_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);
}
…
}
最终来到
_dispatch_barrier_sync_f_inline(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func, uintptr_t dc_flags)
{
dispatch_tid tid = _dispatch_tid_self();
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;
// 死锁
if (unlikely(!_dispatch_queue_try_acquire_barrier_sync(dl, tid))) {
return _dispatch_sync_f_slow(dl, ctxt, func, DC_FLAG_BARRIER, dl,
DC_FLAG_BARRIER | dc_flags);
}
if (unlikely(dl->do_targetq->do_targetq)) {
return _dispatch_sync_recurse(dl, ctxt, func,
DC_FLAG_BARRIER | dc_flags);
}
_dispatch_introspection_sync_begin(dl);
_dispatch_lane_barrier_sync_invoke_and_complete(dl, ctxt, func
DISPATCH_TRACE_ARG(_dispatch_trace_item_sync_push_pop(
dq, ctxt, func, dc_flags | DC_FLAG_BARRIER)));
}
注意 _dispatch_sync_f_slow() 这个函数是不是有点眼熟 GCD死锁的时候 调用堆栈里就能看到这个函数。
_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_trace_item_push(top_dq, &dsc);
__DISPATCH_WAIT_FOR_QUEUE__(&dsc, dq);
…
}
__DISPATCH_WAIT_FOR_QUEUE__(dispatch_sync_context_t dsc, dispatch_queue_t dq)
{
uint64_t dq_state = _dispatch_wait_prepare(dq);
if (unlikely(_dq_state_drain_locked_by(dq_state, dsc->dsc_waiter))) {
DISPATCH_CLIENT_CRASH((uintptr_t)dq_state,
"dispatch_sync called on queue "
"already owned by current thread");
}
…
}
dsc->dsc_waiter是当前线程的tid dq_state是当前队列的状态
这个状态标记录了当前queue的tid
通过_dq_state_drain_locked_by查询当前队列lock的tid和传进来的tid是否一致 如果一致说明这个队列已经被当前线程lock 造成死锁。
大致理解为:
线程A 在串行队列Q 中加入task1那么Q.dq_state会和A.tid第一次绑定并阻塞线程等待task1执行
如果此时task1向队列Q又同步提交task2 ,那么Q.dq_state会查询到Q队列已经和线程A绑定过 还没有解绑 那么会触发死锁异常。