主队列
队列代表口子宽窄,一次一个也可能一次多个,依赖于线程执行
dispatch_queue_main_t
dispatch_get_main_queue(void)
{
return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
}
断点NSlog行,bt查看堆栈信息,底层为libdispatch库 ```objectivec dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"CC 函数分析");
});
- thread #2, queue = ‘com.apple.root.default-qos’, stop reason = breakpoint 1.1
- frame #0: 0x0000000102323d07 001—-函数与队列
__29-[ViewController viewDidLoad]_block_invoke(.block_descriptor=0x00000001023270e8) at ViewController.m:25:9 frame #1: 0x000000010c4d2578 libdispatch.dylib
_dispatch_call_block_and_release + 12 frame #2: 0x000000010c4d374e libdispatch.dylib_dispatch_client_callout + 8 frame #3: 0x000000010c4d5b96 libdispatch.dylib
_dispatch_queue_override_invoke + 1026 frame #4: 0x000000010c4e51b0 libdispatch.dylib_dispatch_root_queue_drain + 351 frame #5: 0x000000010c4e5b0f libdispatch.dylib
_dispatch_worker_thread2 + 135 frame #6: 0x000000010c9a6453 libsystem_pthread.dylib_pthread_wqthread + 244 frame #7: 0x000000010c9a5467 libsystem_pthread.dylib
start_wqthread + 15 ```底层源码
dispatch
- frame #0: 0x0000000102323d07 001—-函数与队列
查看dispatch底层源码
- 上述DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q)中,dispatch_queue_main_t是类型,_dispatch_main_q是对象
- 查看_dispatch_main_q底层源码
- dq_label -> 主队列字符串,比如我们自定义的”com.company.XXXX”,主队列中是”com.apple.main-thread”
- dq_atomic_flags -> DQF_WIDTH(1)代表串行队列,可以通过下面dispatch_queue_create底层源码验证
- dq_serialnum = 1 -> 只是一个标识,下面会讲到
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_queue_create
我们只需要关注返回值dispatch_queue_t,return _dispatch_trace_queue_create(dq)._dq
- _dispatch_trace_queue_create,苹果经常开启痕迹抓取,用到了trace函数
- 主要就是dq,dq是通过_dispatch_object_alloc申请开辟内存得到的,然后调用_dispatch_queue_init构造函数初始化
dispatch_queue_create底层源码
- Step 1: Normalize arguments (qos, overcommit, tq),优先级相关处理,包括label赋值
Step 2: Initialize the queue
- 申请内存 -> dispatch_lane_t dq = _dispatch_object_alloc(…)
- 构造函数初始化 -> _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判断是否是并发,如果是传一个WIDTH_MAX,否则传1 -> 验证上述dqf_width(1)代表串行队列 ```objectivec 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) // dispatch_qos_t qos = dqai.dqai_qos;
…
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->dq_label = label; dq->dq_priority = _dispatch_priority_make((dispatch_qos_t)dqai.dqai_qos,
dqai.dqai_relpri);
if (overcommit == dispatchqueue_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; } ```
_dispatch_queue_init
进一步查看_dispatch_queue_init函数
dqf |= DQF_WIDTH(width) ,width为1时,dqf就是串行队列
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;
}
dq_serialnum只是一个标识, dq->dq_serialnum = os_atomic_inc_orig(&_dispatch_queue_serial_numbers, relaxed)
- 取地址_dispatch_queue_serial_numbers,其值为17,具体定义如下
- 1 代表主队列
- 2 代表mgr_q
- 3 代表mgr_root_q
- 4-15代表全局队列 global queues
- 17代表自定义创建队列 workloop_fallback_q
// skip zero
// 1 - main_q
// 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
- 取地址_dispatch_queue_serial_numbers,其值为17,具体定义如下
GCD底层源码继承链
- 无论是主队列还是自定队列,都是用dispatch_queue_t类型来接收
- dispatch_queue_t -> dispatch_queue_s -> dispatch_object_s -> _os_object_s -> dispatch_object_t
- 类比class -> objc_class(结构体类型) -> objc_object,所以我们来查看dispatch_queue_s具体结构
dispatch_object_s根类是dispatch_object_t
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;
问题补充
以下代码打印结果不固定,但一定是大于等于5
- 异步全局并发队列进行num自增,多线程对一个值进行+1操作,结果不固定
- 但跳出while的条件一定是大于等于5,所以结果在大于等于5时打印 ```objectivec
(void)MTDemo{ while (self.num < 5) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.num++;
});
} NSLog(@”end : %d”,self.num); // 0-5 0 } ```
以下代码打印结果同样不固定,但结果一定小于等于10000
- for循环定值运行10000次,多线程操作,耗时操作,有可能结果未回来,所以结果小于等于10000 ```objectivec
(void)KSDemo{
for (int i= 0; i<10000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
self.num++;
});
} NSLog(@”end : %d”,self.num); // > 10000 } ```
- atomic虽然保证的读写安全,但不能保证多条线程去多的时候安全,因此要进行加锁处理
GCD中Block执行流程
dispatch_sync
源码验证
- dq为队列,work为block,是对block的封装
- _dispatch_Block_invoke宏定义 ->
define _dispatch_Block_invoke(bb) \ ((dispatch_function_t)((struct Block_layout *)bb)->invoke)
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);
}
_dispatch_sync_f底层进入_dispatch_sync_f_inline,通过符号断点进入到_dispatch_sync_f_slow(经常死锁也在这里)中
继续符号断点,调用顺序为_dispatch_sync_function_invoke -> _dispatch_sync_function_invoke_inline -> _dispatch_client_callout ->
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_client_callout中调用了f(ctxt),对block进行了调用,参数ctxt/dispatch_function_f
void
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
_dispatch_get_tsd_base();
void *u = _dispatch_get_unwind_tsd();
if (likely(!u)) return f(ctxt);
_dispatch_set_unwind_tsd(NULL);
f(ctxt);
_dispatch_free_unwind_tsd();
_dispatch_set_unwind_tsd(u);
}
bt验证
断点block处,bt查看堆栈信息
- 查看block调用同样为_dispatch_sync_function_invoke -> _dispatch_client_callout
(lldb) bt
* thread #1, queue = 'com.apple.root.default-qos', stop reason = breakpoint 2.1
* frame #0: 0x0000000100634d07 001---函数与队列`__29-[ViewController viewDidLoad]_block_invoke(.block_descriptor=0x00000001006380e8) at ViewController.m:25:9
frame #1: 0x000000010a7e474e libdispatch.dylib`_dispatch_client_callout + 8
frame #2: 0x000000010a7e8fbc libdispatch.dylib`_dispatch_sync_function_invoke + 127
dispatch_async
源码验证
- 调用流程,dispatch_async ->
- _dispatch_continuation_async -> dx_push(宏)-> dq_push,在init.c文件中赋值.dq_push,全局队列.dp_push = _dispatch_root_queue_push
_dispatch_root_queue_push流程
_dispatch_root_queue_push_inline -> _dispatch_root_queue_poke -> _dispatch_root_queue_poke_slow -> _dispatch_root_queues_init
void
_dispatch_root_queue_push(dispatch_queue_global_t rq, dispatch_object_t dou,
dispatch_qos_t qos)
{
#if DISPATCH_USE_KEVENT_WORKQUEUE
dispatch_deferred_items_t ddi = _dispatch_deferred_items_get();
if (unlikely(ddi && ddi->ddi_can_stash)) {
dispatch_object_t old_dou = ddi->ddi_stashed_dou;
dispatch_priority_t rq_overcommit;
rq_overcommit = rq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT;
if (likely(!old_dou._do || rq_overcommit)) {
dispatch_queue_global_t old_rq = ddi->ddi_stashed_rq;
dispatch_qos_t old_qos = ddi->ddi_stashed_qos;
ddi->ddi_stashed_rq = rq;
ddi->ddi_stashed_dou = dou;
ddi->ddi_stashed_qos = qos;
_dispatch_debug("deferring item %p, rq %p, qos %d",
dou._do, rq, qos);
if (rq_overcommit) {
ddi->ddi_can_stash = false;
}
if (likely(!old_dou._do)) {
return;
}
// push the previously stashed item
qos = old_qos;
rq = old_rq;
dou = old_dou;
}
}
#endif
#if HAVE_PTHREAD_WORKQUEUE_QOS
if (_dispatch_root_queue_push_needs_override(rq, qos)) {
return _dispatch_root_queue_push_override(rq, dou, qos);
}
#else
(void)qos;
#endif
_dispatch_root_queue_push_inline(rq, dou, dou, 1);
}
_dispatch_root_queues_init,其_dispatch_root_queues_init_once参数是一个单例
_dispatch_root_queues_init(void)
{
dispatch_once_f(&_dispatch_root_queues_pred, NULL,
_dispatch_root_queues_init_once);
}
_dispatch_root_queues_init_once
- 先判断了线程状态_dispatch_root_queue_init_pthread_pool,判断可使用线程池
配置工作队列
#if DISPATCH_USE_KEVENT_SETUP
struct pthread_workqueue_config cfg = {
.version = PTHREAD_WORKQUEUE_CONFIG_VERSION,
.flags = 0,
.workq_cb = 0,
.kevent_cb = 0,
.workloop_cb = 0,
.queue_serialno_offs = dispatch_queue_offsets.dqo_serialnum,
#if PTHREAD_WORKQUEUE_CONFIG_VERSION >= 2
.queue_label_offs = dispatch_queue_offsets.dqo_label,
#endif
};
多work进行包装,cfg.workq_cb = _dispatch_worker_thread2
- _dispatch_worker_thread2 -> _dispatch_root_queue_drain -> _dispatch_continuation_pop_inline -> _dispatch_continuation_invoke_inline -> _dispatch_client_callout
qos封装流程,_dispatch_continuation_init -> _dispatch_continuation_init_f -> _dispatch_continuation_priority_set
- **_dispatch_continuation_priority_set 任务优先级封装**
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);
}
bt验证
异步函数中封装了qos,因为异步函数异步调用,过程无序,任务回调是异步。