我們都知道,程序啟動(dòng)就會(huì)創(chuàng)建一個(gè)主線程來執(zhí)行程序,我們先看一下默認(rèn)開啟的主線程的相關(guān)信息。在main函數(shù)打一個(gè)斷點(diǎn),看函數(shù)調(diào)用棧:

可以看到當(dāng)前線程:Queue: com.apple.main-thread(serial),它的名字是com.apple.main-thread,它的類型是serial也就是串行隊(duì)列。
這個(gè)主線程是什么時(shí)候創(chuàng)建又是怎么調(diào)用的呢?我們可以看到在main函數(shù)之前,主線程就已經(jīng)被創(chuàng)建好,猜測(cè)應(yīng)該是dyld鏈接之后,main函數(shù)之前創(chuàng)建的。那我們?cè)趺醋C明呢?這就要去libdispatch源碼中找線索了。
在源碼中找類似init操作看有沒有主線程相關(guān)的初始化。全局搜索dispatch_get_main_queue(,找到下面實(shí)現(xiàn):
DISPATCH_INLINE DISPATCH_ALWAYS_INLINE DISPATCH_CONST DISPATCH_NOTHROW
dispatch_queue_main_t
dispatch_get_main_queue(void)
{
return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
}
#define DISPATCH_GLOBAL_OBJECT(type, object) ((type)&(object))
這個(gè)宏定義第一個(gè)參數(shù)type是類型,值是object。也就是說dispatch_queue_main_t是類型,_dispatch_main_q這個(gè)才是真正的值。全局進(jìn)行搜索,發(fā)現(xiàn)結(jié)果有很多,這個(gè)變量要調(diào)用一定會(huì)有賦值的地方,嘗試搜索_dispatch_main_q =,就會(huì)發(fā)現(xiàn)只有一個(gè)地方賦值:
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,
};
從上面代碼可以看到,主隊(duì)列的名字com.apple.main-thread,跟我們上面看函數(shù)調(diào)用棧的結(jié)果一樣,也就是沒找錯(cuò)地方。主隊(duì)列的類型DQF_WIDTH(1),串行隊(duì)列,很多人說.dq_serialnum = 1看到這個(gè)num = 1就是主隊(duì)列,其實(shí)不是,這只是隊(duì)列的編號(hào),怎么證明呢?串行隊(duì)列必然相對(duì)并發(fā)隊(duì)列有某些特性,我們找的就是這些特性來證明。
我們創(chuàng)建隊(duì)列,都是用dispatch_queue_create(<#const char * _Nullable label#>, <#dispatch_queue_attr_t _Nullable attr#>)這個(gè)函數(shù)來創(chuàng)建,現(xiàn)在來研究下創(chuàng)建的底層實(shí)現(xiàn)。
全局搜索dispatch_queue_create(con,為什么要加(con因?yàn)槲覀円宜牡讓訉?shí)現(xiàn),第一個(gè)參數(shù)是const類型,這樣搜索結(jié)果更少方便定位。
dispatch_queue_t
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)
{
return _dispatch_lane_create_with_target(label, attr,
DISPATCH_TARGET_QUEUE_DEFAULT, true);
}
找到_dispatch_lane_create_with_target的實(shí)現(xiàn),有100多行代碼,我們研究的重點(diǎn)是看它創(chuàng)建的隊(duì)列是什么,也就是返回的是什么隊(duì)列,所以我們先關(guān)注返回值。
返回值是_dispatch_trace_queue_create(dq)._dq,里面trace的含義就是方便追蹤,不是關(guān)注重點(diǎn),重點(diǎn)是里面的dq,我們看dq是如何創(chuàng)建的。從_dispatch_lane_create_with_target方法中找相關(guān)代碼:
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));
第一行是開辟內(nèi)存空間,第二行是構(gòu)造函數(shù)??礃?gòu)造函數(shù)第三個(gè)參數(shù),dqai.dqai_concurrent ? DISPATCH_QUEUE_WIDTH_MAX : 1,命名意思比較明顯,判斷是不是并發(fā)隊(duì)列,如果是傳max,如果不是并發(fā)隊(duì)列(即串行隊(duì)列),參數(shù)就傳1。
我們?cè)倏礃?gòu)造函數(shù)的實(shí)現(xiàn),看這個(gè)參數(shù)是如何使用的:

可以看到參數(shù)使用dqf |= DQF_WIDTH(width);,也就是為什么我們上面說DQF_WIDTH(1)是隊(duì)列的類型。
再看下dq_serialnum,它這個(gè)值是根據(jù)os_atomic_inc_orig創(chuàng)建
#define os_atomic_inc_orig(p, m) \
os_atomic_add_orig((p), 1, m)
#define os_atomic_add_orig(p, v, m) \
_os_atomic_c11_op_orig((p), (v), m, add, +)
#define _os_atomic_c11_op_orig(p, v, m, o, op) \
atomic_fetch_##o##_explicit(_os_atomic_c11_atomic(p), v, \
memory_order_##m)
這個(gè)函數(shù)最后就會(huì)變成atomic_fetch_add_explicit(_os_atomic_c11_atomic(p), 1, memory_order_relaxed),這個(gè)宏一層層封裝最后就是C11標(biāo)準(zhǔn)的函數(shù),atomic_fetch_add_explicit可以理解是把前兩個(gè)參數(shù)想加并返回,_os_atomic_c11_atomic表示是原子操作。
那看下第一個(gè)參數(shù)的值_dispatch_queue_serial_numbers是什么:
// 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
extern unsigned long volatile _dispatch_queue_serial_numbers;
可以看到1是主隊(duì)列的意思,4-15全局隊(duì)列,我們用dispatch_get_global_queue創(chuàng)建的隊(duì)列為什么沒有2、3在注釋中可以得到解釋。
這里有個(gè)想法,這個(gè)隊(duì)列和線程的num是不是一致的呢?我們創(chuàng)建幾個(gè)線程并打?。?/p>

明顯看到線程num有等于3(不一定一次運(yùn)行就出現(xiàn),我也是運(yùn)行了好多次),也就是線程的num和隊(duì)列的num并不是一個(gè)東西,不要混淆了。
我們分別獲取4種不同的線程打印下線程信息:

去源碼中搜索com.apple.root.default-qos,可以看到全局隊(duì)列對(duì)應(yīng)的num是10
_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT, DISPATCH_PRIORITY_FLAG_FALLBACK,
.dq_label = "com.apple.root.default-qos",
.dq_serialnum = 10,
),
我們現(xiàn)在再回到_dispatch_lane_create_with_target這個(gè)方法中,看第一行代碼
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
這行代碼的意義就是對(duì)線程一些信息進(jìn)行面向?qū)ο蟮姆庋b。再全局搜索dispatch_queue_attr_info_t看下他的結(jié)構(gòu):
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;
一個(gè)用位域表示的結(jié)構(gòu)體。
看下_dispatch_queue_attr_to_info實(shí)現(xiàn),里面有個(gè)小細(xì)節(jié),如果dqa是空的話,就直接返回。

dispatch_queue_create創(chuàng)建隊(duì)列的時(shí)候,如果attr傳空,通過dqai.dqai_concurrent判斷就會(huì)是串行隊(duì)列,如果attr傳DISPATCH_QUEUE_SERIAL,可以看到這個(gè)宏的實(shí)現(xiàn)#define DISPATCH_QUEUE_SERIAL NULL也是空,所以他們是等價(jià)的,都是創(chuàng)建串行隊(duì)列。
隊(duì)列的類型
無論我們直接獲取主隊(duì)列或者全局隊(duì)列又或者自己創(chuàng)建的隊(duì)列,最后我們接收的類型都是dispatch_queue_t,點(diǎn)進(jìn)去看這個(gè)類型:DISPATCH_DECL(dispatch_queue);,這里我們可以看到有好幾個(gè)宏定義,他們判斷不同,第一個(gè)#if OS_OBJECT_USE_OBJC,正常會(huì)走到這個(gè)if里面。
再繼續(xù)點(diǎn)就可以看到
#define DISPATCH_DECL(name) OS_OBJECT_DECL_SUBCLASS(name, dispatch_object)
繼續(xù)往下看發(fā)現(xiàn)沒有了,我們只能從源碼中搜索OS_OBJECT_DECL_SUBCLASS,找到三個(gè)宏定義:
#define OS_OBJECT_DECL_SUBCLASS(name, super) DISPATCH_DECL(name)
這個(gè)相當(dāng)于跟上面DISPATCH_DECL宏定義死循環(huán)了,不是這個(gè)。
#define OS_OBJECT_DECL_SUBCLASS_SWIFT(name, super) \
OS_EXPORT OS_OBJECT_OBJC_RUNTIME_VISIBLE \
OS_OBJECT_DECL_IMPL_CLASS(name, OS_OBJECT_CLASS(super))
這個(gè)的條件是#if OS_OBJECT_SWIFT3,也不是這個(gè)。
就剩下一個(gè):
#define OS_OBJECT_DECL_SUBCLASS(name, super) \
OS_OBJECT_DECL_IMPL(name, <OS_OBJECT_CLASS(super)>)
繼續(xù)往下探索這個(gè)宏定義實(shí)現(xiàn):
#define OS_OBJECT_DECL_IMPL(name, ...) \
OS_OBJECT_DECL_PROTOCOL(name, __VA_ARGS__) \
typedef NSObject<OS_OBJECT_CLASS(name)> \
* OS_OBJC_INDEPENDENT_CLASS name##_t
#define OS_OBJECT_DECL_PROTOCOL(name, ...) \
@protocol OS_OBJECT_CLASS(name) __VA_ARGS__ \
@end
#define OS_OBJECT_CLASS(name) OS_##name
DISPATCH_DECL(dispatch_queue);OS_OBJECT_DECL_SUBCLASS(dispatch_queue, dispatch_object)OS_OBJECT_DECL_IMPL(dispatch_queue, <OS_OBJECT_CLASS(dispatch_object)>)-
OS_OBJECT_DECL_PROTOCOL(dispatch_queue, <OS_OBJECT_CLASS(dispatch_object)>)
typedef NSObject<OS_OBJECT_CLASS(dispatch_queue)>
* OS_OBJC_INDEPENDENT_CLASS dispatch_queue_t -
@protocol OS_OBJECT_CLASS(dispatch_queue) <OS_OBJECT_CLASS(dispatch_object)>
@end
typedef NSObject<OS_OBJECT_CLASS(dispatch_queue)>
* OS_OBJC_INDEPENDENT_CLASS dispatch_queue_t -
@protocol os_dispatch_queue <os_dispatch_object>
@end
typedef NSObject<os_dispatch_queue>
* OS_OBJC_INDEPENDENT_CLASS dispatch_queue_t
也就是dispatch_queue_t本質(zhì)是一個(gè)滿足os_dispatch_queue協(xié)議的對(duì)象。
第二個(gè)#elif defined(__cplusplus) && !defined(__DISPATCH_BUILDING_DISPATCH__),判斷是C++第二個(gè)條件是YES,也就是說底層C++實(shí)現(xiàn)可能會(huì)走到這個(gè)if
#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_s類型繼承dispatch_object_s的結(jié)構(gòu)體。
在源碼中我們還能看到一個(gè)聯(lián)合體:
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;
dispatch_object_t這個(gè)可以是聯(lián)合體里面的各種類型。
之后的條件就沒必要看了,基本不會(huì)走。
它的底層結(jié)構(gòu)因?yàn)榈讓邮荂++,所以我們看第二個(gè),看下dispatch_queue_s結(jié)構(gòu)體的實(shí)現(xiàn):
struct dispatch_queue_s {
DISPATCH_QUEUE_CLASS_HEADER(queue, void *__dq_opaque1);
/* 32bit hole on LP64 */
} DISPATCH_ATOMIC64_ALIGN;
#define DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__) \
_DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__); \
/* LP64 global queue cacheline boundary */ \
unsigned long dq_serialnum; \
const char *dq_label; \
DISPATCH_UNION_LE(uint32_t volatile dq_atomic_flags, \
const uint16_t dq_width, \
const uint16_t __dq_opaque2 \
); \
dispatch_priority_t dq_priority; \
union { \
struct dispatch_queue_specific_head_s *dq_specific_head; \
struct dispatch_source_refs_s *ds_refs; \
struct dispatch_timer_source_refs_s *ds_timer_refs; \
struct dispatch_mach_recv_refs_s *dm_recv_refs; \
struct dispatch_channel_callbacks_s const *dch_callbacks; \
}; \
int volatile dq_sref_cnt
#define _DISPATCH_QUEUE_CLASS_HEADER(x, __pointer_sized_field__) \
DISPATCH_OBJECT_HEADER(x); \
__pointer_sized_field__; \
DISPATCH_UNION_LE(uint64_t volatile dq_state, \
dispatch_lock dq_state_lock, \
uint32_t dq_state_bits \
)
#endif
#define DISPATCH_OBJECT_HEADER(x) \
struct dispatch_object_s _as_do[0]; \
_DISPATCH_OBJECT_HEADER(x)
#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; \
void *do_finalizer
#define OS_OBJECT_STRUCT_HEADER(x) \
_OS_OBJECT_HEADER(\
const struct x##_vtable_s *do_vtable, \
do_ref_cnt, \
do_xref_cnt)
#define _OS_OBJECT_HEADER(isa, ref_cnt, xref_cnt) \
isa; /* must be pointer-sized */ \
int volatile ref_cnt; \
int volatile xref_cnt
一層一層宏包裝的繼承鏈。
GCD任務(wù)塊執(zhí)行時(shí)機(jī)
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"1");
});
上面代碼在全局并發(fā)隊(duì)列同步執(zhí)行一個(gè)打印,那這個(gè)block塊里面的代碼是什么時(shí)候?qū)崿F(xiàn)的呢?從源碼中找線索:
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);
}
這里重點(diǎn)關(guān)注work即可,就是我們執(zhí)行的block。
搜索_dispatch_Block_invoke可以看到是個(gè)宏定義:
#define _dispatch_Block_invoke(bb) \
((dispatch_function_t)((struct Block_layout *)bb)->invoke)
執(zhí)行invoke也就是這個(gè)就是work的調(diào)用,繼續(xù)看_dispatch_sync_f是從哪調(diào)用過來的,
DISPATCH_NOINLINE
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);
}
ctxt就是work,func就是block函數(shù)。

我們看到_dispatch_sync_f_inline函數(shù)有好幾個(gè)return,到底走哪個(gè)也不好判斷,這時(shí)候我們就把return對(duì)應(yīng)函數(shù)加到符號(hào)斷點(diǎn)里面,看到底走哪個(gè)。


看到斷點(diǎn)走到了_dispatch_sync_f_slow位置,在源碼中搜索_dispatch_sync_f_slow的實(shí)現(xiàn),里面也是有幾個(gè)return,我們故技重施,繼續(xù)添加符號(hào)斷點(diǎn)并且重新運(yùn)行,

看到后面走到的_dispatch_sync_function_invoke這個(gè)方法,
static void
_dispatch_sync_function_invoke(dispatch_queue_class_t dq, void *ctxt,
dispatch_function_t func)
{
_dispatch_sync_function_invoke_inline(dq, ctxt, func);
}
static inline void
_dispatch_sync_function_invoke_inline(dispatch_queue_class_t dq, void *ctxt,
dispatch_function_t func)
{
dispatch_thread_frame_s dtf;
_dispatch_thread_frame_push(&dtf, dq);
_dispatch_client_callout(ctxt, func);
_dispatch_perfmon_workitem_inc();
_dispatch_thread_frame_pop(&dtf);
}
參數(shù)ctxt就是之前的work,func就是之前block包裝的函數(shù),跟這個(gè)有關(guān)的就是_dispatch_client_callout(ctxt, func);,全局搜索_dispatch_client_callout(void,有幾個(gè)地方:
static inline void
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
return f(ctxt);
}
void
_dispatch_client_callout(void *ctxt, dispatch_function_t f)
{
@try {
return f(ctxt);
}
@catch (...) {
objc_terminate();
}
}
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);
}
這兩個(gè)無論調(diào)用哪個(gè),核心思想都是調(diào)用f(ctxt),也就是block中的函數(shù)。
總結(jié)下dispatch_sync中block調(diào)用:
dispatch_sync_dispatch_sync_f_dispatch_sync_f_inline_dispatch_sync_f_slow_dispatch_sync_function_invoke_dispatch_sync_function_invoke_inline_dispatch_client_calloutf(ctxt)
在block中打個(gè)斷點(diǎn),看下函數(shù)調(diào)用棧:

跟我們分析一致。
接下來我們看下dispatch_async中block的調(diào)用時(shí)機(jī)。
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"1");
});
全局搜索dispatch_async(dis
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);
}
我們還是關(guān)注work,找_dispatch_continuation_init的實(shí)現(xiàn)

unlikely不用關(guān)注,再找_dispatch_continuation_init_f實(shí)現(xiàn)


也就是說,qos = _dispatch_continuation_init(dc, dq, work, 0, dc_flags);這行代碼的意義就是把block進(jìn)行對(duì)應(yīng)的封裝以及優(yōu)先級(jí)處理。因?yàn)槭钱惒降?,所以需要?yōu)先級(jí)來進(jìn)行函數(shù)執(zhí)行的參考和依據(jù)。
函數(shù)想要執(zhí)行,肯定就要依賴下面的代碼_dispatch_continuation_async(dq, dc, qos, dc->dc_flags);

#define dx_push(x, y, z) dx_vtable(x)->dq_push(x, y, z)
因?yàn)楹瘮?shù)最后包裝在qos里面,所以我們關(guān)注z這個(gè)參數(shù),全局搜索dq_push

全局并發(fā)隊(duì)列是在這賦值,找_dispatch_root_queue_push實(shí)現(xiàn):

里面第三個(gè)參數(shù)是函數(shù)封裝,并沒有找到相關(guān)的調(diào)用,看最后方法,繼續(xù)找:
DISPATCH_ALWAYS_INLINE
static inline void
_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;
if (unlikely(os_mpsc_push_list(os_mpsc(dq, dq_items), hd, tl, do_next))) {
return _dispatch_root_queue_poke(dq, n, 0);
}
}


static inline void
_dispatch_root_queues_init(void)
{
dispatch_once_f(&_dispatch_root_queues_pred, NULL,
_dispatch_root_queues_init_once);
}
這里面封裝單利,執(zhí)行一次_dispatch_root_queues_init_once,單利的原理我們?cè)谙旅鏁?huì)分析。

我們先看下函數(shù)調(diào)用棧:

函數(shù)調(diào)用是從_dispatch_worker_thread2這個(gè)函數(shù)調(diào)用過來,在方法里面找這個(gè)函數(shù)相關(guān)內(nèi)容:

這個(gè)就是底層
pthread的相關(guān)封裝,它是通過workloop來控制是否調(diào)用,這個(gè)workloop又是通過OS控制,受CPU的調(diào)度處理。
死鎖分析
dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"1");
dispatch_sync(queue, ^{
NSLog(@"2");
});
NSLog(@"3");
});
我們看上面的一段代碼,運(yùn)行就會(huì)發(fā)現(xiàn)崩潰,可以看到崩潰的函數(shù)調(diào)用棧:

死鎖崩潰我們可以看到先走到_dispatch_sync_f_slow函數(shù),然后再走__DISPATCH_WAIT_FOR_QUEUE__發(fā)生崩潰,那現(xiàn)在從源碼分析一下什么情況下回產(chǎn)生死鎖。
我們上面已經(jīng)分析到,dispatch_sync的流程,一開始流程沒有區(qū)別:
dispatch_sync_dispatch_sync_f_dispatch_sync_f_inline
走到這都一樣,但是接下來,就不太一樣了,看likely(dq->dq_width == 1)這個(gè)條件,上面分析過dq_width為1時(shí)為串行隊(duì)列,死鎖就是在串行隊(duì)列才會(huì)有,所以我們看這個(gè)if里面的代碼:return _dispatch_barrier_sync_f(dq, ctxt, func, dc_flags);
static void
_dispatch_barrier_sync_f(dispatch_queue_t dq, void *ctxt,
dispatch_function_t func, uintptr_t dc_flags)
{
_dispatch_barrier_sync_f_inline(dq, ctxt, func, dc_flags);
}

因?yàn)槲覀兩厦嬉呀?jīng)看到,死鎖會(huì)走到_dispatch_sync_f_slow函數(shù),所以看這個(gè)方法我們只需要找到這個(gè)函數(shù)的調(diào)用,又回到之前調(diào)用的流程中函數(shù),但是這次判斷就會(huì)不一樣了:

為了驗(yàn)證我們分析是正確的,首先運(yùn)行看函數(shù)調(diào)用:

再看源碼中__DISPATCH_WAIT_FOR_QUEUE__方法:

#define DISPATCH_CLIENT_CRASH(c, x) do { \
_dispatch_set_crash_log_cause_and_message((c), \
"BUG IN CLIENT OF LIBDISPATCH: " x); \
_dispatch_hardware_crash(); \
} while (0)
就可以看到源碼分析中輸出的message和我們運(yùn)行匯編message一模一樣,所以分析正確!其實(shí)在messag里面已經(jīng)說明了什么情況會(huì)死鎖,dispatch_sync調(diào)用的隊(duì)列,已經(jīng)是當(dāng)前的線程中了。
流程沒問題了,雖然message我們可以看出端倪,但是我們還是想知道代碼如何判斷會(huì)產(chǎn)生死鎖,也就是說,什么條件下會(huì)走到這些代碼呢。最重要的還是要看__DISPATCH_WAIT_FOR_QUEUE__方法里面的判斷
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");
}
當(dāng)條件滿足時(shí),才會(huì)走到下面的方法,我們現(xiàn)在就分析這個(gè)條件。
dsc->dsc_waiter就是當(dāng)前線程的id,dsc是上面參數(shù)傳過來的,

#define _dispatch_tid_self() ((dispatch_tid)(_dispatch_get_tsd_base()->tid))
dq_state = _dispatch_wait_prepare(dq);代表當(dāng)前隊(duì)列的狀態(tài)。
_dq_state_drain_locked_by這個(gè)函數(shù)實(shí)現(xiàn):
static inline bool
_dq_state_drain_locked_by(uint64_t dq_state, dispatch_tid tid)
{
return _dispatch_lock_is_locked_by((dispatch_lock)dq_state, tid);
}
static inline bool
_dispatch_lock_is_locked_by(dispatch_lock lock_value, dispatch_tid tid)
{
// equivalent to _dispatch_lock_owner(lock_value) == tid
return ((lock_value ^ tid) & DLOCK_OWNER_MASK) == 0;
}
這里面的掩碼DLOCK_OWNER_MASK是很大的值#define DLOCK_OWNER_MASK ((dispatch_lock)0xfffffffc),也就是前面如果是0的話,返回YES就會(huì)造成死鎖,也就是state和tid相同時(shí),會(huì)死鎖,也就是說當(dāng)前線程要等待,然后你又調(diào)用當(dāng)前線程執(zhí)行,就會(huì)造成死鎖。
單利原理分析
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"once");
});
gcd單利寫法如上面代碼,底層是怎么實(shí)現(xiàn)的呢,我們現(xiàn)在來研究一下。
在源碼中全局搜索dispatch_once找到它的實(shí)現(xiàn):
void
dispatch_once(dispatch_once_t *val, dispatch_block_t block)
{
dispatch_once_f(val, block, _dispatch_Block_invoke(block));
}

typedef struct dispatch_gate_s {
dispatch_lock dgl_lock;
} dispatch_gate_s, *dispatch_gate_t;
typedef struct dispatch_once_gate_s {
union {
dispatch_gate_s dgo_gate;
uintptr_t dgo_once;
};
} dispatch_once_gate_s, *dispatch_once_gate_t;
判斷能否進(jìn)入函數(shù)執(zhí)行:
static inline bool
_dispatch_once_gate_tryenter(dispatch_once_gate_t l)
{
return os_atomic_cmpxchg(&l->dgo_once, DLOCK_ONCE_UNLOCKED,
(uintptr_t)_dispatch_lock_value_for_self(), relaxed);
}
調(diào)用函數(shù)并廣播:
static void
_dispatch_once_callout(dispatch_once_gate_t l, void *ctxt,
dispatch_function_t func)
{
_dispatch_client_callout(ctxt, func);
_dispatch_once_gate_broadcast(l);
}
流程總結(jié)如下:
- 先試類型強(qiáng)制轉(zhuǎn)換成
dispatch_once_gate_t,標(biāo)記這個(gè)是否已經(jīng)做過和一些鎖 - 判斷
dgo_once等于DLOCK_ONCE_DONE,相當(dāng)于做過,直接return - 如果嘗試加鎖失敗,直接把
dgo_once設(shè)置成DLOCK_ONCE_DONE - 判斷
l沒有被加鎖,也就是沒有別的線程操作,調(diào)用函數(shù)并且廣播 - 等待其他人開鎖