底層源碼分析措近。
首先從創(chuàng)建隊(duì)列講起踢涌, dispatch_queue_create函數(shù)
dispatch_queue_create 內(nèi)部調(diào)用了
dispatch_queue_t
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
{
// attr我們一般傳??????????????DISPATCH_QUEUE_SERIAL未蝌,??DISPATCH_QUEUE_CONCURRENT??巢钓, ??NULL嗅钻,
// ??DISPATCH_QUEUE_SERIAL????????就是 NULL
return _dispatch_lane_create_with_target(label, attr,
DISPATCH_TARGET_QUEUE_DEFAULT, true);
}
_dispatch_lane_create_with_target 函數(shù) 當(dāng)我們?cè)诖蜷_(kāi)libdispatch找到這個(gè)函數(shù)的時(shí)候發(fā)現(xiàn)舀透,很難讀枝冀。但是我們需要找到讀它的方法 重點(diǎn)就是看他的返回值返回了什么司训。從返回值上獲取關(guān)鍵線索去排查(這里就不粘貼這個(gè)方法全部的代碼了有興趣的去自己下載觀看)
return _dispatch_trace_queue_create(dq)._dq;
- 從這個(gè)返回值上面我們發(fā)現(xiàn)了返回的是 將當(dāng)前函數(shù)獲取的dq 傳進(jìn)_dispatch_trace_queue_create中進(jìn)行包裝旱捧。又將其屬性 _dq返回独郎。所以dq就是 我們要檢查的重點(diǎn)。
進(jìn)入到 dispatch_trace_queue_create 函數(shù),查看 _dq屬性 和穿進(jìn)去的dq做了什么
static inline dispatch_queue_class_t
_dispatch_trace_queue_create(dispatch_queue_class_t dqu)
{
///對(duì)傳進(jìn)來(lái)的dq進(jìn)行包裝處理
/// 僅在啟用跟蹤時(shí)進(jìn)行分派
_dispatch_only_if_ktrace_enabled({
uint64_t dq_label[4] = {0}; // So that we get the right null termination
dispatch_queue_t dq = dqu._dq;
strncpy((char *)dq_label, (char *)dq->dq_label ?: "", sizeof(dq_label));
_dispatch_ktrace2(DISPATCH_QOS_TRACE_queue_creation_start,
dq->dq_serialnum,
_dispatch_priority_to_pp_prefer_fallback(dq->dq_priority));
_dispatch_ktrace4(DISPATCH_QOS_TRACE_queue_creation_end,
dq_label[0], dq_label[1], dq_label[2], dq_label[3]);
});
///將傳進(jìn)來(lái) dq 傳進(jìn) 函數(shù) 并返回
return _dispatch_introspection_queue_create(dqu);
}
- 從上面的函數(shù)中 看 又將 最外層 dq 傳進(jìn)了一個(gè) _dispatch_introspection_queue_create 函數(shù)進(jìn)行了包裝處理
進(jìn)入到 _dispatch_introspection_queue_create
_dispatch_introspection_queue_create(dispatch_queue_t dq)
{
dispatch_queue_introspection_context_t dqic;
size_t sz = sizeof(struct dispatch_queue_introspection_context_s);
if (!_dispatch_introspection.debug_queue_inversions) {
sz = offsetof(struct dispatch_queue_introspection_context_s,
__dqic_no_queue_inversion);
}
///初始化了個(gè) dqic
dqic = _dispatch_calloc(1, sz);
///將 dq賦值給 _dq
dqic->dqic_queue._dq = dq;
if (_dispatch_introspection.debug_queue_inversions) {
LIST_INIT(&dqic->dqic_order_top_head);
LIST_INIT(&dqic->dqic_order_bottom_head);
}
dq->do_finalizer = dqic;
_dispatch_unfair_lock_lock(&_dispatch_introspection.queues_lock);
LIST_INSERT_HEAD(&_dispatch_introspection.queues, dqic, dqic_list);
_dispatch_unfair_lock_unlock(&_dispatch_introspection.queues_lock);
DISPATCH_INTROSPECTION_INTERPOSABLE_HOOK_CALLOUT(queue_create, dq);
if (DISPATCH_INTROSPECTION_HOOK_ENABLED(queue_create)) {
_dispatch_introspection_queue_create_hook(dq);
}
return upcast(dq)._dqu;
}
- 這里我們看到了 dq就等于 _dq
- 再往下看已經(jīng)沒(méi)有意義 而dq就是我們要研究的枚赡。
繼續(xù)查看 upcast()
static inline dispatch_object_t
upcast(dispatch_object_t dou)
{
return dou;
}
經(jīng)過(guò)這幾層函數(shù)的追蹤判斷 我們并沒(méi)有看到我們想要的并指導(dǎo)了 dq就是我們要研究的重點(diǎn)
那么回到 最上面的_dispatch_lane_create_with_target的函數(shù) 中尋找 dq做了什么氓癌。
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_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s)); // 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)); // init
dq->dq_label = label;
dq->dq_priority = _dispatch_priority_make((dispatch_qos_t)dqai.dqai_qos,
dqai.dqai_relpri);
if (overcommit == _dispatch_queue_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_lane_create_with_target 函數(shù) 中我們看到了 始化 _dispatch_object_alloc, _dispatch_queue_init 。這不就是 初始化 和 init嗎贫橙? 不由得想起了我們平常開(kāi)發(fā)的 [NSObjc alloc] init]; 在這里 _dispatch_object_alloc進(jìn)行了初始化空間的工作贪婉。init進(jìn)行了區(qū)分是 當(dāng)前是否是 串行 還是 并行 ,串行 給了 1 并行給了 DISPATCH_QUEUE_WIDTH_MAX 的操作(并行 給了 最大的寬度)
在 _dispatch_queue_init 里面我們看到了根據(jù) dqai.dqai_concurrent 來(lái)區(qū)分 并行 和串行卢肃。
下面我們?cè)诋?dāng)前函數(shù)看一下 dqai
static dispatch_queue_t
_dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa,
dispatch_queue_t tq, bool legacy)
{
// dqai 創(chuàng)建 ///根據(jù)傳進(jìn)來(lái) dqa serio concurrent NULL 獲取 dqai
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
....省略
}
發(fā)現(xiàn)第一行就根據(jù) 傳進(jìn)來(lái)的 要?jiǎng)?chuàng)建什么樣的隊(duì)列 進(jìn)行了 dqai的創(chuàng)建 我看一下_dispatch_queue_attr_to_info 函數(shù)
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) { // null 默認(rèn)
dqai.dqai_concurrent = true;
return dqai;
}
#endif
if (dqa < _dispatch_queue_attrs ||
dqa >= &_dispatch_queue_attrs[DISPATCH_QUEUE_ATTR_COUNT]) {
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;
}
- 通過(guò)此函數(shù)的處理我們看到了 無(wú)論你傳NULL 還是 DISPATCH_QUEUE_SERIAL 都是 為默認(rèn)就是串行隊(duì)列疲迂。
我們繼續(xù)返回到_dispatch_lane_create_with_target 繼續(xù) 查找 dqai
//
// Step 2: Initialize the queue
//
if (legacy) {
// if any of these attributes is specified, use non legacy classes
if (dqai.dqai_inactive || dqai.dqai_autorelease_frequency) {
legacy = false;
}
}
const void *vtable;
dispatch_queue_flags_t dqf = legacy ? DQF_MUTABLE : 0;
/*----------------- 這區(qū)間里面是在做什么才顿? ------------------------*/
if (dqai.dqai_concurrent) {
// OS_dispatch_queue_concurrent
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
vtable = DISPATCH_VTABLE(queue_serial);
}
/*---------------------------------------------------------------*/
switch (dqai.dqai_autorelease_frequency) {
case DISPATCH_AUTORELEASE_FREQUENCY_NEVER:
dqf |= DQF_AUTORELEASE_NEVER;
break;
case DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM:
dqf |= DQF_AUTORELEASE_ALWAYS;
break;
}
if (label) {
const char *tmp = _dispatch_strdup_if_mutable(label);
if (tmp != label) {
dqf |= DQF_LABEL_NEEDS_FREE;
label = tmp;
}
}
// 開(kāi)辟內(nèi)存空間
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s)); // alloc
/// 區(qū)分 串行 還是 并發(fā)
_dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
(dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0)); // init
- 看上面代碼 標(biāo)記出來(lái)的注釋 這是在干什么? 如果是創(chuàng)建并發(fā)隊(duì)列 就vtable = DISPATCH_VTABLE(queue_concurrent)尤蒿。串行隊(duì)列 vtable = DISPATCH_VTABLE(queue_serial);
繼續(xù)搜索 DISPATCH_VTABLE
#define DISPATCH_VTABLE(name) DISPATCH_OBJC_CLASS(name)
繼續(xù)搜 DISPATCH_OBJC_CLASS
#define DISPATCH_OBJC_CLASS(name) (&DISPATCH_CLASS_SYMBOL(name))
繼續(xù)搜 DISPATCH_CLASS_SYMBOL
#define DISPATCH_CLASS_SYMBOL(name) OS_dispatch_##name##_class
#define DISPATCH_CLASS(name) OS_dispatch_##name
- 我的天 這騷操作 進(jìn)行了 參數(shù)拼接 也就是如過(guò)是 并行就是 這么個(gè)東西 OS_dispatch_
queue_concurrent
; 如果是 串行就是這樣
OS_dispatch_queue_serial
; 看到這里不由得發(fā)出一個(gè)疑問(wèn) 隊(duì)列也是一個(gè)對(duì)象郑气? -
## 在編譯的時(shí)候 會(huì)去掉。name就是 傳進(jìn)來(lái)的參數(shù)進(jìn)行拼接腰池。
迫不及待的去打印一下生成的隊(duì)列對(duì)象尾组。
截屏2020-11-07 下午1.43.35.png - 從這看出隊(duì)列 也是一個(gè)對(duì)象,那它一定有 對(duì)isa的操作示弓,在哪里讳侨?我們先往下面看
繼續(xù)回到這
/*----------------- 這區(qū)間里面是在做什么? ------------------------*/
if (dqai.dqai_concurrent) {
// OS_dispatch_queue_concurrent
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
vtable = DISPATCH_VTABLE(queue_serial);
}
/*---------------------------------------------------------------*/
- 這里我們也就知道了 這里是在設(shè)置類 的類型
既然創(chuàng)建了一個(gè)對(duì)象 在 創(chuàng)建完之前 它isa 避乏;類的東西 已經(jīng)確認(rèn)完畢爷耀,那他在哪里?跟任何一個(gè)類 都是一摸摸一樣樣的拍皮。一個(gè)對(duì)象alloc的時(shí)候它前面必然會(huì)做歹叮,它的父類啊,它的isa的都會(huì)指向完畢铆帽。
回到 _dispatch_object_alloc的地方
///設(shè)置 類的 信息
if (dqai.dqai_concurrent) {
// OS_dispatch_queue_concurrent
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
vtable = DISPATCH_VTABLE(queue_serial);
}
switch (dqai.dqai_autorelease_frequency) {......}
if (label) {......}
// 開(kāi)辟內(nèi)存空間
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s)); // alloc
/// 區(qū)分 串行 還是 并發(fā)
_dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
(dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0)); // init
/// 參數(shù)賦值
- 我們看到 將類的信息傳入了 _dispatch_object_alloc 里面咆耿。
搜索 _dispatch_object_alloc
#pragma mark dispatch_object_t
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
}
搜索 _os_object_alloc_realized
_os_object_alloc_realized(const void *cls, size_t size)
{
_os_object_t obj;
dispatch_assert(size >= sizeof(struct _os_object_s));
while (unlikely(!(obj = calloc(1u, size)))) {
_dispatch_temporary_resource_shortage();
}
obj->os_obj_isa = cls;
return obj;
}
- 由此可以看出 隊(duì)列 也是個(gè)對(duì)象。
隊(duì)列底層探索總結(jié)
- 我們創(chuàng)建一個(gè)隊(duì)列爹橱,傳入的屬性(DISPATCH_QUEUE_SERIAL/NULL/DISPATCH_QUEUE_CONCURRENT)決定了下層的_dispatch_queue_init 的 DISPATCH_QUEUE_WIDTH_MAX 和 1 的區(qū)別萨螺。
- 我們創(chuàng)建出來(lái)的 queue 也是一個(gè)對(duì)象 ,底層也需要 alloc init進(jìn)行創(chuàng)建愧驱,alloc過(guò)程中也會(huì)指定 class 的類型.class的設(shè)置 是由底層宏定義拼接而成慰技。
- 并發(fā)隊(duì)列最大并發(fā)數(shù)是多少?DISPATCH_QUEUE_WIDTH_MAX 真么大组砚。
#define DISPATCH_QUEUE_WIDTH_FULL 0x1000ull
#define DISPATCH_QUEUE_WIDTH_MAX (DISPATCH_QUEUE_WIDTH_FULL - 2)
/// 0x1000ull - 2 = 4094
以上就是對(duì)隊(duì)列的底層探究 下面來(lái)到 函數(shù)底層探究篇章
dispatch_async 異步函數(shù)底層探究
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;
// 任務(wù)包裝器 - 接受 - 保存 - 函數(shù)式
// 保存 block
qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);
_dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}
- 這里我們看到 初始化了一個(gè)任務(wù)包裝器 init的時(shí)候 將 dc(初始化的任務(wù)包裝器)吻商;dq(傳進(jìn)來(lái)的隊(duì)列);work(傳進(jìn)來(lái)的block任務(wù)) 等傳進(jìn)了 _dispatch_continuation_init 方法
進(jìn)入 _dispatch_continuation_init 我們看做了什么操作
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)
{
///將work進(jìn)行copy獲取 得到 *ctxt指針
void *ctxt = _dispatch_Block_copy(work);
dc_flags |= DC_FLAG_BLOCK | DC_FLAG_ALLOCATED;
///大多數(shù)不會(huì)走這里
if (unlikely(_dispatch_block_has_private_data(work))) {
dc->dc_flags = dc_flags;
///將 work副本存入到了 dc包裝器里
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);
}
/// 根據(jù)任務(wù) 獲取 調(diào)用 func
dispatch_function_t func = _dispatch_Block_invoke(work);
if (dc_flags & DC_FLAG_CONSUME) {
///指定執(zhí)行函數(shù) 為 _dispatch_call_block_and_release糟红;
func = _dispatch_call_block_and_release;
}
return _dispatch_continuation_init_f(dc, dqu, ctxt, func, flags, dc_flags);
}
這里看到 將傳進(jìn)的任務(wù) work 進(jìn)行了copy操作 并放進(jìn)了 dc任務(wù)包裝器里 并又 將 dc ; dq 隊(duì)列 傳進(jìn)了 _dispatch_continuation_init_slow 大多數(shù)不會(huì)走這條支線 但是 其原理 基本一致艾帐。
根據(jù)任務(wù) work 獲取 func ,在某些條件下 將指定執(zhí)行函數(shù) 為 _dispatch_call_block_and_release 并將 dc,dqu, ctxt ,func,等傳進(jìn)了 _dispatch_continuation_init_f
我們搜索 _dispatch_continuation_init_f
static inline dispatch_qos_t
_dispatch_continuation_init_f(dispatch_continuation_t dc,
dispatch_queue_class_t dqu, void *ctxt, dispatch_function_t f,
dispatch_block_flags_t flags, uintptr_t dc_flags)
{
pthread_priority_t pp = 0;
dc->dc_flags = dc_flags | DC_FLAG_ALLOCATED;
dc->dc_func = f; /// 將func方法存進(jìn) dc包裝器
dc->dc_ctxt = ctxt;/// 將 ctxt block 的上下文指針盆偿。
// in this context DISPATCH_BLOCK_HAS_PRIORITY means that the priority
// should not be propagated, only taken from the handler if it has one
///優(yōu)先級(jí)的處理
if (!(flags & DISPATCH_BLOCK_HAS_PRIORITY)) {
pp = _dispatch_priority_propagate();
}
/// 存入處理過(guò)的 dc
_dispatch_continuation_voucher_set(dc, flags);
return _dispatch_continuation_priority_set(dc, dqu, pp, flags);
}
-
我們看到這里就基本上明白了 block 任務(wù)塊先被包裝了起來(lái)柒爸,在合適的時(shí)機(jī) 將響應(yīng)任務(wù)∈屡ぃ看到這里 我們?nèi)タ匆幌?異步函數(shù)的調(diào)用堆棧捎稚。在繼續(xù)分析 看他到底是由誰(shuí)調(diào)用起來(lái)的。
截屏2020-11-08 下午6.59.27.png - 這里好像明白了什么 和我們?cè)创a分析的 一抹抹一樣樣。dispatch_call_block_and_release 函數(shù)發(fā)起的調(diào)用阳藻。
- 流程 start_wqthread - > _pthread_wqthread -> _dispatch_worker_thread2 -> _dispatch_root_queue_drain -> _dispatch_async_redirect_invoke -> _ dispatch_continuation_pop -> _dispatch_client_callout ->
_dispatch_call_block_and_release
通過(guò)上面的操作 我們了解 任務(wù)包裝器大概是如何 將 外部傳進(jìn)的block進(jìn)行保存的晰奖。 通過(guò)堆棧也知道了 正是 任務(wù)包裝器保存的 _dispatch_call_block_and_release函數(shù) 發(fā)起的調(diào)用 谈撒。雖說(shuō)我們看到了堆棧調(diào)用流程腥泥,但是具體到每個(gè)函數(shù)干什么 我還需要據(jù)需研究。
下面繼續(xù)回到dispatch_async;函數(shù) 繼續(xù)研究 下面函數(shù)
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;
// 任務(wù)包裝器 - 接受 - 保存 - 函數(shù)式
// 保存 block
qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);
/// 研究它
_dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}
- dq :隊(duì)列對(duì)象啃匿。dc: 包裝了block任務(wù)的包裝器蛔外。qos:策略保證正確的資源分配。dc_flags :標(biāo)簽
搜索 _dispatch_continuation_async
_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 函數(shù) 并將 隊(duì)列信息溯乒,任務(wù)包裝器夹厌,策略 傳進(jìn)并返回。
那 dx_push函數(shù)究竟做了什么裆悄?搜索它
#define dx_push(x, y, z) dx_vtable(x)->dq_push(x, y, z)
#define dx_vtable(x) (&(x)->do_vtable->_os_obj_vtable)
- 發(fā)現(xiàn) dx_push 是一個(gè)宏定義 矛纹,其實(shí)就是 將 隊(duì)列信息 傳進(jìn) dx_vtable(x)得到對(duì)象,并調(diào)用 此對(duì)象的 dq_push函數(shù)光稼。
- 那它這么寫的意義在什么或南?我們只看這個(gè)宏的拆解 可能就 猜到。x為隊(duì)列信息艾君。y為 包裝器采够,z為策略。 通過(guò) x 信息可以獲取不同對(duì)象冰垄。再去調(diào)用不同對(duì)象的同名方法 dq_push 蹬癌。
- 最終執(zhí)行為 dq_push函數(shù)。
搜索 dq_push
- 這里看到發(fā)現(xiàn) 蘋果底層封裝的好屌啊虹茶,dx_push逝薪,會(huì)根據(jù)當(dāng)前隊(duì)列信息,來(lái)尋找,已經(jīng)寫好的vtables[ ]集群蝴罪。每個(gè) vtable對(duì)應(yīng)著 一種隊(duì)列董济。而每個(gè)vtable擁有一模一樣的屬性。這里dq_push就是對(duì)應(yīng)著 并發(fā)隊(duì)列vtable的一個(gè)屬性洲炊。而這個(gè)屬性 是 一個(gè)函數(shù)名字感局。dx_push 的最終形態(tài) 就是 _dispatch_lane_concurrent_push函數(shù)發(fā)起的調(diào)用。為了證明我們的猜想在當(dāng)前環(huán)境 打符號(hào)斷點(diǎn)來(lái)驗(yàn)證暂衡。
將_dispatch_lane_concurrent_push函數(shù)打個(gè)符號(hào)斷點(diǎn) 并運(yùn)行
- 可以的果真來(lái)到了這里 询微,證明我們的猜測(cè)是對(duì)的。
搜索_dispatch_lane_concurrent_push 看他的實(shí)現(xiàn)
DISPATCH_NOINLINE
void
_dispatch_lane_concurrent_push(dispatch_lane_t dq, dispatch_object_t dou,
dispatch_qos_t qos)
{
// <rdar://problem/24738102&24743140> reserving non barrier width
// doesn't fail if only the ENQUEUED bit is set (unlike its barrier
// width equivalent), so we have to check that this thread hasn't
// enqueued anything ahead of this call or we can break ordering
/*如果只設(shè)置了排隊(duì)位狂巢,保留非柵欄寬度不會(huì)失敗(不像它的柵欄)
寬度相等)撑毛,所以我們必須檢查這個(gè)線程沒(méi)有
在這個(gè)調(diào)用之前排隊(duì),或者我們可以打破順序*/
if (dq->dq_items_tail == NULL &&
!_dispatch_object_is_waiter(dou) &&
!_dispatch_object_is_barrier(dou) &&
_dispatch_queue_try_acquire_async(dq)) {
return _dispatch_continuation_redirect_push(dq, dou, qos);
}
_dispatch_lane_push(dq, dou, qos);
}
- 這里判斷當(dāng)前隊(duì)列尾部為空,&& 不是wait 藻雌;&& 不是 barrier && 是 async 那么返回 _dispatch_continuation_redirect_push雌续;
- 而其他環(huán)境 進(jìn)入_dispatch_lane_push
- 這里環(huán)境猜測(cè)會(huì)進(jìn)入這里 。
我們延續(xù)上面符號(hào)斷點(diǎn)再次將_dispatch_continuation_redirect_push 打入一個(gè)符號(hào)斷點(diǎn)并運(yùn)行
- 和猜想一致進(jìn)入了 _dispatch_continuation_redirect_push
搜索_dispatch_continuation_redirect_push 看它的實(shí)現(xiàn)
_dispatch_continuation_redirect_push(dispatch_lane_t dl,
dispatch_object_t dou, dispatch_qos_t qos)
{
///_dispatch對(duì)象是不是重定向
if (likely(!_dispatch_object_is_redirection(dou))) {
dou._dc = _dispatch_async_redirect_wrap(dl, dou);
} else if (!dou._dc->dc_ctxt) {
// find first queue in descending target queue order that has
// an autorelease frequency set, and use that as the frequency for
// this continuation./*找到降序目標(biāo)隊(duì)列中設(shè)置了自動(dòng)釋放頻率的第一個(gè)隊(duì)列胯杭,并使用該頻率作為此后續(xù)操作的頻率*/
dou._dc->dc_ctxt = (void *)
(uintptr_t)_dispatch_queue_autorelease_frequency(dl);
}
dispatch_queue_t dq = dl->do_targetq;
if (!qos) qos = _dispatch_priority_qos(dq->dq_priority);
dx_push(dq, dou, qos);//咦驯杜?怎么又調(diào)用了dx_push在進(jìn)行遞歸
}
首先分析 `if (likely(!_dispatch_object_is_redirection(dou)))
1. 拓展一下 likely
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
- 它其實(shí)是個(gè)宏 誰(shuí)對(duì) _builtin_expect封裝,likely表示更大可能成立做个,unlikely表示更大可能不成立
- 我們看 _dispatch_object_is_redirection 實(shí)現(xiàn)代碼
_dispatch_object_is_redirection(dispatch_object_t dou)
{
return _dispatch_object_has_type(dou,
DISPATCH_CONTINUATION_TYPE(ASYNC_REDIRECT));
}
_dispatch_object_has_type(dispatch_object_t dou, unsigned long type)
{
return _dispatch_object_has_vtable(dou) && dx_type(dou._do) == type;
}
- _dispatch_object_has_vtable(dou) 判斷當(dāng)前隊(duì)列是否有vtable 條件滿足
- dx_type(dou._do) == DISPATCH_CONTINUATION_TYPE(ASYNC_REDIRECT)
這里 看dx_type 是啥
在上面我們也看了 vtables集群 這次一樣 找到 并發(fā)隊(duì)列的 do_type看是什么 鸽心?這里找到為DISPATCH_QUEUE_CONCURRENT_TYPE 再次解析#define dx_type(x) dx_vtable(x)->do_type
在查看DISPATCH_CONTINUATION_TYPE(ASYNC_REDIRECT)DISPATCH_QUEUE_CONCURRENT_TYPE = DISPATCH_OBJECT_SUBTYPE(2, LANE),
再次 解析 DC_ASYNC_REDIRECT_TYPE#define DISPATCH_CONTINUATION_TYPE(name) \ DISPATCH_OBJECT_SUBTYPE(DC_ASYNC_REDIRECT_TYPE, CONTINUATION)
解析了這么多 這里 其實(shí)就是為了證明當(dāng)前會(huì)走進(jìn) 這個(gè)判斷里enum { _DC_USER_TYPE = 0, DC_ASYNC_REDIRECT_TYPE, //在這里 我等于1 DC_MACH_SEND_BARRRIER_DRAIN_TYPE, DC_MACH_SEND_BARRIER_TYPE, DC_MACH_RECV_BARRIER_TYPE, ... };
進(jìn)入到 if判斷 里面 搜索 _dispatch_async_redirect_wrap 看其實(shí)現(xiàn)
_dispatch_async_redirect_wrap(dispatch_lane_t dq, dispatch_object_t dou)
{
dispatch_continuation_t dc = _dispatch_continuation_alloc();//創(chuàng)建新的 任務(wù)包裝器
dou._do->do_next = NULL;
dc->do_vtable = DC_VTABLE(ASYNC_REDIRECT); //
dc->dc_func = NULL;
dc->dc_ctxt = (void *)(uintptr_t)_dispatch_queue_autorelease_frequency(dq);
dc->dc_data = dq;
dc->dc_other = dou._do;
dc->dc_voucher = DISPATCH_NO_VOUCHER;
dc->dc_priority = DISPATCH_NO_PRIORITY;
_dispatch_retain_2(dq); // released in _dispatch_async_redirect_invoke
return dc;
}
- 這里 又初始化了一個(gè)任務(wù)包裝器,并將 任務(wù)包裝器 的do_vtable函數(shù)指定為 DC_VTABLE(ASYNC_REDIRECT);
搜索 DC_VTABLE 看是個(gè)啥
搜索 _dispatch_continuation_vtables[#define DC_VTABLE(name) (&_dispatch_continuation_vtables[DC_ASYNC_REDIRECT_TYPE])
const struct dispatch_continuation_vtable_s _dispatch_continuation_vtables[] = { DC_VTABLE_ENTRY(ASYNC_REDIRECT, .do_invoke = _dispatch_async_redirect_invoke), #if HAVE_MACH DC_VTABLE_ENTRY(MACH_SEND_BARRRIER_DRAIN, .do_invoke = _dispatch_mach_send_barrier_drain_invoke), DC_VTABLE_ENTRY(MACH_SEND_BARRIER, .do_invoke = _dispatch_mach_barrier_invoke), DC_VTABLE_ENTRY(MACH_RECV_BARRIER, .do_invoke = _dispatch_mach_barrier_invoke), DC_VTABLE_ENTRY(MACH_ASYNC_REPLY, .do_invoke = _dispatch_mach_msg_async_reply_invoke), #endif #if HAVE_PTHREAD_WORKQUEUE_QOS DC_VTABLE_ENTRY(WORKLOOP_STEALING, .do_invoke = _dispatch_workloop_stealer_invoke), DC_VTABLE_ENTRY(OVERRIDE_STEALING, .do_invoke = _dispatch_queue_override_invoke), DC_VTABLE_ENTRY(OVERRIDE_OWNING, .do_invoke = _dispatch_queue_override_invoke), #endif #if HAVE_MACH DC_VTABLE_ENTRY(MACH_IPC_HANDOFF, .do_invoke = _dispatch_mach_ipc_handoff_invoke), #endif };
- 看到這里就是 就明白了 dc->do_vtable = DC_VTABLE(ASYNC_REDIRECT) 就是指定 重定向的.do_invoke函數(shù)為 _dispatch_async_redirect_invoke居暖,后面的任務(wù)執(zhí)行就是通過(guò)這個(gè)函數(shù)顽频。 而這個(gè)函數(shù) 正在做什么 就是在準(zhǔn)備及重定向函數(shù) 進(jìn)行包裝。
回到_dispatch_async_redirect_wrap
_dispatch_continuation_redirect_push(dispatch_lane_t dl,
dispatch_object_t dou, dispatch_qos_t qos)
{
if (likely(!_dispatch_object_is_redirection(dou))) {
///將 創(chuàng)建新的任務(wù)包裝器 并指定給當(dāng)前 dispatch_object_t 的任務(wù)包裝太闺,
/// 重定向的.do_invoke函數(shù)為 _dispatch_async_redirect_invoke
dou._dc = _dispatch_async_redirect_wrap(dl, dou);
} else if (!dou._dc->dc_ctxt) {
// find first queue in descending target queue order that has
// an autorelease frequency set, and use that as the frequency for
// this continuation.
dou._dc->dc_ctxt = (void *)
(uintptr_t)_dispatch_queue_autorelease_frequency(dl);
}
///看這里 -----------------------------------------------*/
dispatch_queue_t dq = dl->do_targetq;
if (!qos) qos = _dispatch_priority_qos(dq->dq_priority);
dx_push(dq, dou, qos);
/* -----------------------------------------------*/
}
我們繼續(xù)看代碼中 標(biāo)注的位置 大致看了一眼 發(fā)現(xiàn) 又調(diào)用了 dx_push 函數(shù)糯景。這個(gè)函數(shù)我們上面已經(jīng)分析。它會(huì)根據(jù)當(dāng)前隊(duì)列省骂,去找 vtables里面 集群蟀淮,并找到對(duì)應(yīng) vtable ->do_push 函數(shù)。
-
分析 第一個(gè)參數(shù): 此時(shí) dq = dl->do_targetq 這里這是在干嘛冀宴? dl是當(dāng)前的隊(duì)列 對(duì)象灭贷。 do_targetq:這個(gè)屬性 這不在隊(duì)列初始化底層分析的時(shí)候就見(jiàn)到過(guò)。我們回去再看一眼略贮。它就是 根隊(duì)列(root_queue)甚疟。
回到隊(duì)列初始化函數(shù)瞄一眼 do_targetq屬性。 搜索 _dispatch_lane_create_with_target
由于此函數(shù)太長(zhǎng) 我們只保留了 關(guān)于 do_targetq 屬性的方法(有興趣的自己去搜索源碼)_dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa, dispatch_queue_t tq, bool legacy) ///外邊 tq傳的 NULL : #define DISPATCH_TARGET_QUEUE_DEFAULT NULL ///所以進(jìn)這里 if (!tq) { ///tq 正是主隊(duì)列啊 tq = _dispatch_get_root_queue( qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq; if (unlikely(!tq)) { DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute"); } } /// 1. alloc 出 dq對(duì)象 /// 2. init /// 參數(shù)賦值 dq->do_targetq = tq; _dispatch_object_debug(dq, "%s", __func__); return _dispatch_trace_queue_create(dq)._dq; }
這次我們看明白了這次 dx_push 正是在對(duì) root_queue進(jìn)行操作逃延。
dispatch_queue_t dq = dl->do_targetq; 這句代碼 意思正是在 獲取 root_queue對(duì)象览妖。
再次進(jìn)入 到 dx_push
#define dx_push(x, y, z) dx_vtable(x)->dq_push(x, y, z)
- 上面分析過(guò) 這時(shí)候的dx_vtable(x) x,傳入的主隊(duì)列 所以 查看 關(guān)于主隊(duì)列的vtable 看他的 dq_push指定的函數(shù)是誰(shuí)。
搜索 dq_push 找到關(guān)于 主隊(duì)列的vtable
- 看到這里也就明白這次的dx_push 底層 調(diào)用的 _dispatch_root_queue_push函數(shù)揽祥。
- 不得不說(shuō)蘋果的這操作是真 騷啊讽膏。
老規(guī)矩 打符號(hào)斷點(diǎn)驗(yàn)證
- 果真和我們猜測(cè)的一摸摸 一樣樣。
來(lái)到 _dispatch_root_queue_push
_dispatch_root_queue_push(dispatch_queue_global_t rq, dispatch_object_t dou,
dispatch_qos_t qos)
{
///調(diào)度使用中的隊(duì)列
#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
// 一般情況下拄丰,無(wú)論自定義還是非自定義都會(huì)走進(jìn)這個(gè)條件(比如:dispatch_get_global_queue)
// 里面主要是對(duì)比的是 qos與root隊(duì)列的qos是否 一直府树。基本上都不一致料按,如果不一致走進(jìn)這個(gè) if語(yǔ)句
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);
}
進(jìn)入 _dispatch_root_queue_push_override
DISPATCH_NOINLINE
static void
_dispatch_root_queue_push_override(dispatch_queue_global_t orig_rq,
dispatch_object_t dou, dispatch_qos_t qos)
{
bool overcommit = orig_rq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT;
dispatch_queue_global_t rq = _dispatch_get_root_queue(qos, overcommit);
dispatch_continuation_t dc = dou._dc;
// 這個(gè)_dispatch_object_is_redirection函數(shù)其實(shí)就是return _dispatch_object_has_type(dou,DISPATCH_CONTINUATION_TYPE(ASYNC_REDIRECT));
// 所有自定義隊(duì)列會(huì)走if語(yǔ)句奄侠,如果是dispatch_get_global_queue不會(huì)走if語(yǔ)句
if (_dispatch_object_is_redirection(dc)) {
// no double-wrap is needed, _dispatch_async_redirect_invoke will do
// the right thing
dc->dc_func = (void *)orig_rq;
} else {
// dispatch_get_global_queue來(lái)到這里
dc = _dispatch_continuation_alloc();
// 相當(dāng)于 下面,也就指定了執(zhí)行函數(shù)為 _dispatch_queue_override_innvoke,所以有別與自定義隊(duì)列的invoke函數(shù)载矿。
//DC_VTABLE_ENTRY(OVERRIDE_OWNING,.do_invoke = _dispatch_queue_override_invoke),
dc->do_vtable = DC_VTABLE(OVERRIDE_OWNING);
dc->dc_ctxt = dc;
dc->dc_other = orig_rq;
dc->dc_data = dou._do;
dc->dc_priority = DISPATCH_NO_PRIORITY;
dc->dc_voucher = DISPATCH_NO_VOUCHER;
}
_dispatch_root_queue_push_inline(rq, dc, dc, 1);
}
- 這個(gè)函數(shù)區(qū)分了 自定義隊(duì)列 和 dispatch_get_global_queue 的 do_invoke 屬性 也就是 不同類型隊(duì)列 指定 不同函數(shù)垄潮。
- 回到前面函數(shù)如果不走if 里面 和 當(dāng)前函數(shù)都會(huì)去調(diào)用 _dispatch_root_queue_push_inline;
來(lái)到_dispatch_root_queue_push_inline 進(jìn)行分析
_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;
// 把任務(wù)裝進(jìn)隊(duì)列,大多數(shù)不走近 if語(yǔ)句。
if (unlikely(os_mpsc_push_list(os_mpsc(dq, dq_items), hd, tl, do_next))) {
return _dispatch_root_queue_poke(dq, n, 0);
}
}
- 至此弯洗,我們可以看到旅急,我們裝入到自定義的任務(wù),都被扔到掛靠的root隊(duì)列中去了牡整,所以我們自己創(chuàng)建的隊(duì)列只是一個(gè)代理身份藐吮,真正的管理人是其對(duì)應(yīng)的root隊(duì)列,但同時(shí)這個(gè)隊(duì)列也是被管理的果正。
搜索 _dispatch_root_queue_poke
_dispatch_root_queue_poke(dispatch_queue_global_t dq, int n, int floor)
{
if (!_dispatch_queue_class_probe(dq)) {
return;
}
#if !DISPATCH_USE_INTERNAL_WORKQUEUE
#if DISPATCH_USE_PTHREAD_POOL
if (likely(dx_type(dq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE))
#endif
{
if (unlikely(!os_atomic_cmpxchg2o(dq, dgq_pending, 0, n, relaxed))) {
_dispatch_root_queue_debug("worker thread request still pending "
"for global queue: %p", dq);
return;
}
}
#endif // !DISPATCH_USE_INTERNAL_WORKQUEUE
return _dispatch_root_queue_poke_slow(dq, n, floor);
}
繼續(xù)搜索重點(diǎn)_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;
int r = ENOSYS;
_dispatch_root_queues_init();//重點(diǎn)
...
//do-while循環(huán)創(chuàng)建線程
do {
_dispatch_retain(dq); // released in _dispatch_worker_thread
while ((r = pthread_create(pthr, attr, _dispatch_worker_thread, dq))) {
if (r != EAGAIN) {
(void)dispatch_assume_zero(r);
}
_dispatch_temporary_resource_shortage();
}
} while (--remaining);
...
}
通過(guò)_dispatch_root_queues_init方法注冊(cè)回調(diào)
通過(guò)do-while循環(huán)創(chuàng)建線程炎码,使用pthread_create方法
搜索 _dispatch_root_queues_init
_dispatch_root_queues_init(void)
{
dispatch_once_f(&_dispatch_root_queues_pred, NULL,
_dispatch_root_queues_init_once);
}
- dispatch_once_f 好眼熟的函數(shù) 這不就是單例(后面分析單例底層,這里不做說(shuō)明) 秋泳,其中傳入的func是*_dispatch_root_queues_init_once
我們繼續(xù)搜索 _dispatch_root_queues_init_once 看其實(shí)現(xiàn)
- 發(fā)現(xiàn)了其內(nèi)部不同事務(wù)的調(diào)用句柄都是_dispatch_worker_thread2。
小總結(jié)
1 攒菠、看到這里 我們 先 小總結(jié) 一下 迫皱,異步函數(shù) ,首先 將任務(wù)進(jìn)行包裝 辖众,然后 通過(guò) dxpush 函數(shù) 遞歸 的去重定向到根隊(duì)列 并執(zhí)行 根隊(duì)列 的 dopush 也就是 _dispatch_root_queue_push卓起,并注冊(cè)了 其執(zhí)行句柄 _dispatch_worker_thread2 并看到了 線程的創(chuàng)建。
分析:
此時(shí)此刻 凹炸,我們需要整體的去分析一下 隊(duì)列 是什么戏阅?它是一種數(shù)據(jù)結(jié)構(gòu),并發(fā)隊(duì)列+異步函數(shù)啤它,可以支持同一時(shí)間多條線程同時(shí)執(zhí)行任務(wù)奕筐。那任務(wù)在什么時(shí)候開(kāi)始執(zhí)行?它是就緒狀態(tài)变骡,等待著cpu來(lái)進(jìn)行調(diào)度离赫。 所以
_dispatch_root_queue_push 個(gè)人認(rèn)為 它就是在為任務(wù)分配線程。及丟到 并發(fā)隊(duì)列中塌碌。等待cpu的調(diào)度執(zhí)行渊胸。
2 、打印任務(wù) 調(diào)用棧 我們也看到 任務(wù)的執(zhí)行流程台妆。流程 start_wqthread -> _pthread_wqthread -> _dispatch_worker_thread2 ->_dispatch_root_queue_drain ->_dispatch_async_redirect_invoke ->_dispatch_continuation_pop -> _dispatch_client_callout -> _dispatch_call_block_and_release翎猛。
3 、其中start_wqthread
->_pthread_wqthread
并不在 libdispatch.dylib 源碼之中接剩。我們這里也不過(guò)多分析切厘。我們就將其想象成,cpu來(lái)進(jìn)行調(diào)度即可搂漠。流程已經(jīng)熟悉迂卢。那每個(gè)函數(shù)之間的調(diào)用又發(fā)生了什么 我們下面進(jìn)入到調(diào)用棧到的流程底層源碼實(shí)現(xiàn)分析。
從 _dispatch_worker_thread2 開(kāi)始查看
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();
//跟蹤運(yùn)行時(shí)事件
_dispatch_trace_runtime_event(worker_unpark, dq, 0);
int pending = os_atomic_dec2o(dq, dgq_pending, relaxed);
dispatch_assert(pending >= 0);
/*-----------------------------------調(diào)用這里 主隊(duì)列 線程----------------------------------------------*/
_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);
}
搜索 _dispatch_root_queue_drain
static void
_dispatch_root_queue_drain(dispatch_queue_global_t dq,
dispatch_priority_t pri, dispatch_invoke_flags_t flags)
{
#if DISPATCH_DEBUG
dispatch_queue_t cq;
if (unlikely(cq = _dispatch_queue_get_current())) {
DISPATCH_INTERNAL_CRASH(cq, "Premature thread recycling");
}
#endif
_dispatch_queue_set_current(dq);
_dispatch_init_basepri(pri);
_dispatch_adopt_wlh_anon();
struct dispatch_object_s *item;
bool reset = false;
dispatch_invoke_context_s dic = { };
#if DISPATCH_COCOA_COMPAT
_dispatch_last_resort_autorelease_pool_push(&dic);
#endif // DISPATCH_COCOA_COMPAT
_dispatch_queue_drain_init_narrowing_check_deadline(&dic, pri);
_dispatch_perfmon_start();
// 循環(huán)取出任務(wù)
while (likely(item = _dispatch_root_queue_drain_one(dq))) {
if (reset) _dispatch_wqthread_override_reset();
/*---------------------------------------------------------------------------*/
///調(diào)度出任務(wù)的執(zhí)行函數(shù)
_dispatch_continuation_pop_inline(item, &dic, flags, dq);
/*-------------------------------------------------------------------------*/
reset = _dispatch_reset_basepri_override();
if (unlikely(_dispatch_queue_drain_should_narrow(&dic))) {
break;
}
}
// overcommit or not. worker thread
if (pri & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) {
_dispatch_perfmon_end(perfmon_thread_worker_oc);
} else {
_dispatch_perfmon_end(perfmon_thread_worker_non_oc);
}
#if DISPATCH_COCOA_COMPAT
_dispatch_last_resort_autorelease_pool_pop(&dic);
#endif // DISPATCH_COCOA_COMPAT
_dispatch_reset_wlh();
_dispatch_clear_basepri();
_dispatch_queue_set_current(NULL);
}
搜索 _dispatch_continuation_pop_inline
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();
///監(jiān)聽(tīng)處理方便調(diào)試
if (observer_hooks) observer_hooks->queue_will_execute(dqu._dq);
flags &= _DISPATCH_INVOKE_PROPAGATE_MASK;
/*-------------------研究重點(diǎn)----------------------------*/
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);
}
- 這里我們看到了 我們先看 dx_invoke()這個(gè)分支
- 之前說(shuō)過(guò) dispatch_async是有do_vtable成員變量的,所以會(huì)走進(jìn) 這個(gè)分支而克,又invoke方法指定為_(kāi)dispatch_async_redirect_invoke靶壮,所以執(zhí)行該函數(shù)。
- 相同的员萍,如果是dispatch_get_global_queue也會(huì)走這個(gè)分支腾降,執(zhí)行_dispatch_queue_override_invoke 方法。
搜索dx_invoke
#define dx_invoke(x, y, z) dx_vtable(x)->do_invoke(x, y, z)
- 可以看到 dx_invoke是個(gè)宏定義 是調(diào)用對(duì)象 的do_invoke 屬性 和dx_push 是一摸摸一樣樣的 數(shù)據(jù)結(jié)構(gòu)封裝
- 并且 在 第二次 dx_push 的時(shí)候(也就是由根隊(duì)列發(fā)起push之前的 方法包裝器就已經(jīng)指定do_invoke是_dispatch_async_redirect_invoke ) 就已經(jīng)知道了do_invoke 屬性 是哪個(gè)函數(shù)碎绎。
搜索 _dispatch_async_redirect_invoke
void
_dispatch_async_redirect_invoke(dispatch_continuation_t dc,
dispatch_invoke_context_t dic, dispatch_invoke_flags_t flags)
{
dispatch_thread_frame_s dtf;
struct dispatch_continuation_s *other_dc = dc->dc_other;
dispatch_invoke_flags_t ctxt_flags = (dispatch_invoke_flags_t)dc->dc_ctxt;
// if we went through _dispatch_root_queue_push_override,
// the "right" root queue was stuffed into dc_func
dispatch_queue_global_t assumed_rq = (dispatch_queue_global_t)dc->dc_func;
dispatch_lane_t dq = dc->dc_data;
dispatch_queue_t rq, old_dq;
dispatch_priority_t old_dbp;
if (ctxt_flags) {
flags &= ~_DISPATCH_INVOKE_AUTORELEASE_MASK;
flags |= ctxt_flags;
}
old_dq = _dispatch_queue_get_current();
if (assumed_rq) {
old_dbp = _dispatch_root_queue_identity_assume(assumed_rq);
_dispatch_set_basepri(dq->dq_priority);
} else {
old_dbp = _dispatch_set_basepri(dq->dq_priority);
}
uintptr_t dc_flags = DC_FLAG_CONSUME | DC_FLAG_NO_INTROSPECTION;
_dispatch_thread_frame_push(&dtf, dq);
_dispatch_continuation_pop_forwarded(dc, dc_flags, NULL, {
_dispatch_continuation_pop(other_dc, dic, flags, dq);
});
_dispatch_thread_frame_pop(&dtf);
if (assumed_rq) _dispatch_queue_set_current(old_dq);
_dispatch_reset_basepri(old_dbp);
rq = dq->do_targetq;
while (unlikely(rq->do_targetq && rq != old_dq)) {
_dispatch_lane_non_barrier_complete(upcast(rq)._dl, 0);
rq = rq->do_targetq;
}
// pairs with _dispatch_async_redirect_wrap
_dispatch_lane_non_barrier_complete(dq, DISPATCH_WAKEUP_CONSUME_2);
}
搜索 _dispatch_continuation_pop
_dispatch_continuation_pop(dispatch_object_t dou, dispatch_invoke_context_t dic,
dispatch_invoke_flags_t flags, dispatch_queue_class_t dqu)
{
_dispatch_continuation_pop_inline(dou, dic, flags, dqu._dq);
}
搜索_dispatch_continuation_pop_inline
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();
///監(jiān)聽(tīng)處理方便調(diào)試
if (observer_hooks) observer_hooks->queue_will_execute(dqu._dq);
flags &= _DISPATCH_INVOKE_PROPAGATE_MASK;
/*-------------------研究重點(diǎn)----------------------------*/
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);
}
- 這個(gè)函數(shù)好眼熟 又回到了這里 只不過(guò)這次走的else
搜索_dispatch_continuation_invoke_inline
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_continuation_invoke_inline(dispatch_object_t dou,
dispatch_invoke_flags_t flags, dispatch_queue_class_t dqu)
{
dispatch_continuation_t dc = dou._dc, dc1;
dispatch_invoke_with_autoreleasepool(flags, {
uintptr_t dc_flags = dc->dc_flags;
// Add the item back to the cache before calling the function. This
// allows the 'hot' continuation to be used for a quick callback.
//
// The ccache version is per-thread.
// Therefore, the object has not been reused yet.
// This generates better assembly.
_dispatch_continuation_voucher_adopt(dc, dc_flags);
if (!(dc_flags & DC_FLAG_NO_INTROSPECTION)) {
_dispatch_trace_item_pop(dqu, dou);
}
if (dc_flags & DC_FLAG_CONSUME) {
dc1 = _dispatch_continuation_free_cacheonly(dc);
} else {
dc1 = NULL;
}
if (unlikely(dc_flags & DC_FLAG_GROUP_ASYNC)) {
_dispatch_continuation_with_group_invoke(dc);
} else {
_dispatch_client_callout(dc->dc_ctxt, dc->dc_func);
_dispatch_trace_item_complete(dc);
}
if (unlikely(dc1)) {
_dispatch_continuation_free_to_cache_limit(dc1);
}
});
_dispatch_perfmon_workitem_inc();
}
搜索 _dispatch_client_callout
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
return f(ctxt);
}
- 看到這里 此時(shí)外部的block任務(wù) 就會(huì)執(zhí)行了螃壤。而此時(shí)的f 是是什么? ctxt 是什么筋帖?
f: _dispatch_call_block_and_release
ctxt: block任務(wù)的上下文的指針奸晴。