什么是GCD
答案參考官方文檔毡代。
什么是隊列
隊列是一種特殊的線性表阅羹,特殊之處在于它只允許在表的前端(front)進行刪除操作,而在表的后端(rear)進行插入操作教寂,和棧一樣捏鱼,隊列是一種操作受限制的線性表。進行插入操作的端稱為隊尾酪耕,進行刪除操作的端稱為隊頭导梆。
GCD中的隊列
隊列的分類
隊列總的來說可以分為串行隊列和并行隊列兩種,但是在iOS中的GCD由于主隊列和全局隊列的特殊性迂烁,我們需要單獨討論看尼,在這里我們把GCD中的隊列細分為四種隊列:串行隊列、并行隊列盟步、主隊列和全局并行隊列藏斩。示例:
// 串行隊列
dispatch_queue_t serial = dispatch_queue_create("com.dongjianxiong", DISPATCH_QUEUE_SERIAL);
//并行隊列
dispatch_queue_t conque = dispatch_queue_create("com.dongjianxiong", DISPATCH_QUEUE_CONCURRENT);
// 主隊列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//全局并行隊列
dispatch_queue_t globQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- 串行隊列串行隊列中,提交到隊列里的block是按循序執(zhí)行的却盘,而且是一個執(zhí)行完才能執(zhí)行下一個狰域。串行隊列可以通dispatch_queue_create()函數(shù)創(chuàng)建,第二個參數(shù)可以是DISPATCH_QUEUE_SERIAL或者NULL:
dispatch_queue_t serial = dispatch_queue_create("com.dongjianxiong", DISPATCH_QUEUE_SERIAL);
- 并行隊列隊列里中的block可以同時調(diào)用多個黄橘,不需要等到前面的block執(zhí)行完兆览。并行隊列可以通dispatch_queue_create()函數(shù)創(chuàng)建,第二個參數(shù)可以是DISPATCH_QUEUE_CONCURRENT:
dispatch_queue_t conque = dispatch_queue_create("com.dongjianxiong", DISPATCH_QUEUE_CONCURRENT);
并行隊列的創(chuàng)建流程跟串行隊列是一樣的旬陡,不同前面已經(jīng)提到過拓颓,主要是隊列的類型和最大并行數(shù)。并行隊列的類型為OS_dispatch_queue_concurrent描孟,最大并行數(shù)為DISPATCH_QUEUE_WIDTH_MAX驶睦,是個宏定義,定義為:
#define DISPATCH_QUEUE_WIDTH_FULL 0x1000ull
#define DISPATCH_QUEUE_WIDTH_POOL (DISPATCH_QUEUE_WIDTH_FULL - 1)
#define DISPATCH_QUEUE_WIDTH_MAX (DISPATCH_QUEUE_WIDTH_FULL - 2)
DISPATCH_QUEUE_WIDTH_FULL是16進制匿醒,0x1000ull轉換成10進制為4096场航,所以并行隊列的最大并行數(shù)DISPATCH_QUEUE_WIDTH_MAX為4094。
- 主隊列本身也是個串行隊列廉羔,它的特殊性在于它是和主線程綁定的溉痢。主線程自動創(chuàng)建runloop,主隊列里的block由runloop來調(diào)用。值得注意的一點是孩饼,主隊列只在主線程執(zhí)行台猴,而主線執(zhí)行的不一定是主隊列的。主隊列無法被修改没咙,調(diào)用 dispatch_suspend(), dispatch_resume(), dispatch_set_context()等這些方法操作主線程是無效的赞草。我們可以通過函數(shù)dispatch_get_main_queue獲取:
dispatch_queue_t mainQueue = dispatch_get_main_queue();
- 全局并行隊列實際上也是一個并行隊列梯码,它與普通并行隊列相比不一樣的地方是它是由系統(tǒng)創(chuàng)建的宝泵,并且隊列里的block是根據(jù)系統(tǒng)管理的線程池來調(diào)度的執(zhí)行的。全局并行隊列在系統(tǒng)管理的線程池之上提供了優(yōu)先級桶轩娶,系統(tǒng)將根據(jù)需求和負載情況決定為這個線程池分配多少線程儿奶。系統(tǒng)會盡力保持良好的并行水平,當現(xiàn)有工作線程在系統(tǒng)調(diào)用中阻塞時鳄抒,將創(chuàng)建新的線程闯捎。
全局并行隊列是一個共享資源,因此它需要保證每個使用全局隊列的用戶提交的任務不能無限量提交任務嘁酿,特別是在遇到阻塞時隙券,避免創(chuàng)建大量的線程。
可以通過函數(shù)dispatch_get_global_queue()獲饶炙尽娱仔;同時它也是不能被修改的,調(diào)用Calls to dispatch_suspend(), dispatch_resume(), dispatch_set_context()等對它進行操作時無效的游桩。
通過dispatch_get_global_queue()函數(shù)來獲取牲迫。第一個參數(shù)表示優(yōu)先級。這里要說明是借卧,全局隊列它不是像主隊列那樣只有一個盹憎,而是一組隊列。不同的優(yōu)先級隊列是不一樣的铐刘,默認優(yōu)先級是DISPATCH_QUEUE_PRIORITY_DEFAULT陪每,它的值是0,第二個參數(shù)是保留參數(shù)镰吵,正常要傳0檩禾。優(yōu)先級的值都是系統(tǒng)設定好的,目前就給我們開放了幾個優(yōu)先級:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
隊列dispatch_queue_t的本質
- dispatch_queue_t是怎么來的
通過dispatch_queue_create函數(shù)可以創(chuàng)建一個隊列dispatch_queue_t:
dispatch_queue_t queue = dispatch_queue_create("com.dongjianxiong", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t是什么疤祭?怎么來的盼产?跟蹤dispatch_queue_t的聲明,發(fā)現(xiàn)是通過宏定義聲明的:
DISPATCH_DECL(dispatch_queue);
#define DISPATCH_DECL(name) OS_OBJECT_DECL_SUBCLASS(name, dispatch_object)
#define OS_OBJECT_DECL_SUBCLASS(name, super) \
OS_OBJECT_DECL_IMPL(name, <OS_OBJECT_CLASS(super)>)
#define OS_OBJECT_CLASS(name) OS_##name
#if OS_OBJECT_USE_OBJC
#import <objc/NSObject.h>
#if __has_attribute(objc_independent_class)
#define OS_OBJC_INDEPENDENT_CLASS __attribute__((objc_independent_class))
#endif // __has_attribute(objc_independent_class)
#ifndef OS_OBJC_INDEPENDENT_CLASS
#define OS_OBJC_INDEPENDENT_CLASS
#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
這其中name其實就是dispatch_queue勺馆,最后一行轉化一下大概就是:
typedef NSObject<OS_dispatch_queue> *dispatch_queue_t戏售;
其實通過編譯后的C++代碼也能得出相同的結果:
// @protocol OS_dispatch_queue <OS_dispatch_object> /* @end */
typedef NSObject/*<OS_dispatch_queue>*/ * __attribute__((objc_independent_class)) dispatch_queue_t;
// @protocol OS_dispatch_queue_global <OS_dispatch_queue> /* @end */
typedef NSObject/*<OS_dispatch_queue_global>*/ * __attribute__((objc_independent_class)) dispatch_queue_global_t;
// @protocol OS_dispatch_queue_serial <OS_dispatch_queue> /* @end */
typedef NSObject/*<OS_dispatch_queue_serial>*/ * __attribute__((objc_independent_class)) dispatch_queue_serial_t;
// @protocol OS_dispatch_queue_main <OS_dispatch_queue_serial> /* @end */
typedef NSObject/*<OS_dispatch_queue_main>*/ * __attribute__((objc_independent_class)) dispatch_queue_main_t;
// @protocol OS_dispatch_queue_concurrent <OS_dispatch_queue> /* @end */
typedef NSObject/*<OS_dispatch_queue_concurrent>*/ * __attribute__((objc_independent_class)) dispatch_queue_concurrent_t;
這里證明了dispatch_queue_t其實就是一個OC對象侨核,它的類是OS_dispatch_queue,dispatch_queue_t是OS_dispatch_queue的實現(xiàn)灌灾。
在我們不只看到dispatch_queue_t 的由來搓译,還有它的四個子類。其實這里可以看出OS_dispatch_queue實際上只是一個抽象類紧卒,我們使用的是它的具體的四個子類侥衬,這四個子類的實現(xiàn)分別是dispatch_queue_serial_t(串行隊列)、dispatch_queue_concurrent_t(并行隊列)跑芳、dispatch_queue_main_t(主隊列)和 dispatch_queue_global_t(全局并行隊列)。
- 隊列的繼承關系
這里以串行隊列為例直颅,打印它們繼承鏈:
id queueClass = object_getClass(serial);
while (queueClass != nil) {
NSLog(@"%@",queueClass);
queueClass = [queueClass superclass];
}
打印結果:
2021-08-22 12:24:12.708284+0800 GCDDemo[40888:22219369] OS_dispatch_queue_serial
2021-08-22 12:24:13.977272+0800 GCDDemo[40888:22219369] OS_dispatch_queue
2021-08-22 12:24:15.226658+0800 GCDDemo[40888:22219369] OS_dispatch_object
2021-08-22 12:24:16.567031+0800 GCDDemo[40888:22219369] OS_object
2021-08-22 12:24:17.128303+0800 GCDDemo[40888:22219369] NSObject
這里可以看出隊列的基類也是NSObject博个。事實上所有GCD相關的對象基類都是NSObject。
- 隊列的底層結構
GCD對象雖然是OC對象功偿,但是它的底層結構體并不是直接使用NSObject盆佣,它有自己底層結構_os_object_s結構體:
typedef struct _os_object_s {
_OS_OBJECT_HEADER(
const _os_object_vtable_s *os_obj_isa,
os_obj_ref_cnt,
os_obj_xref_cnt);
} _os_object_s;
typedef struct _os_object_s *_os_object_t;
它也有isa指針os_obj_isa,也有對應的類械荷,在os_obj_isa中:
typedef struct _os_object_vtable_s {
_OS_OBJECT_CLASS_HEADER();
} _os_object_vtable_s;
//
static const _os_object_vtable_s _os_object_vtable;
同時它有自己的對象創(chuàng)建共耍、內(nèi)存管理等相關的方法:
_os_object_t
_os_object_alloc(const void *cls, size_t size);
_os_object_t
_os_object_alloc_realized(const void *cls, size_t size);
void _os_object_dealloc(_os_object_t object);
_os_object_t
_os_object_retain(_os_object_t object);
_os_object_t
_os_object_retain_with_resurrect(_os_object_t obj);
void
_os_object_release(_os_object_t object);
隊列的底層結構也是以_os_object_s模板創(chuàng)建的。
隊列的創(chuàng)建
通過查看dispatch_queue_create()函數(shù)源碼了解隊列創(chuàng)建過程吨瞎。隊列創(chuàng)建主要是在dispatch_lane_create_with_target()函數(shù)中實現(xiàn)的痹兜。它主要做一下幾件事情:
- 根據(jù)是DISPATCH_QUEUE_SERIAL或者DISPATCH_QUEUE_CONCURRENT創(chuàng)建一個dispatch_queue_attr_info_t結構體:
// 創(chuàng)建dqai,dqa表示DISPATCH_QUEUE_SERIAL或者DISPATCH_QUEUE_CONCURRENT
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
//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;
- 確定對象類型
根據(jù)之前創(chuàng)建的dqai確定類型颤诀,DISPATCH_VTABLE宏定義中課獲取它的類字旭,這串行隊列的類為OS_dispatch_queue_serial,而并行的為OS_dispatch_queue_concurrent:
const void *vtable;
dispatch_queue_flags_t dqf = legacy ? DQF_MUTABLE : 0;
if (dqai.dqai_concurrent) {
// OS_dispatch_queue_concurrent
vtable = DISPATCH_VTABLE(queue_concurrent);
} else {
//OS_dispatch_queue_serial
vtable = DISPATCH_VTABLE(queue_serial);
}
通過DISPATCH_VTABLE拿到vtable(類信息):
#define DISPATCH_VTABLE(name) DISPATCH_OBJC_CLASS(name)
#define DISPATCH_OBJC_CLASS(name) (&DISPATCH_CLASS_SYMBOL(name))
#define DISPATCH_CLASS_SYMBOL(name) OS_dispatch_##name##_class
- 隊列的alloc
根據(jù)不同的類創(chuàng)建不同的隊列queue:
// alloc
dispatch_lane_t dq = _dispatch_object_alloc(vtable,
sizeof(struct dispatch_lane_s));
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
}
inline _os_object_t
_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;
}
實際上創(chuàng)建一個_os_object_t結構體崖叫,并初始化isa指針遗淳,指向對應的類。
- 隊列init
// init
_dispatch_queue_init(dq, dqf, dqai.dqai_concurrent ?
DISPATCH_QUEUE_WIDTH_MAX : 1, DISPATCH_QUEUE_ROLE_INNER |
(dqai.dqai_inactive ? DISPATCH_QUEUE_INACTIVE : 0));
初始化隊列時會根據(jù)dqai.dqai_concurrent 判斷是串行隊列還是并行隊列心傀。這里是串行隊列屈暗,所以最大并行數(shù)為1,如果是并行隊列脂男,那么最大并行數(shù)為DISPATCH_QUEUE_WIDTH_MAX:
#define DISPATCH_QUEUE_WIDTH_FULL 0x1000ull
#define DISPATCH_QUEUE_WIDTH_POOL (DISPATCH_QUEUE_WIDTH_FULL - 1)
#define DISPATCH_QUEUE_WIDTH_MAX (DISPATCH_QUEUE_WIDTH_FULL - 2)
DISPATCH_QUEUE_WIDTH_FULL的值為0x1000ull养叛,16進制,轉化成10進制就是4096疆液,那DISPATCH_QUEUE_WIDTH_MAX=4096-2=4094一铅,最大并行數(shù)4094。DISPATCH_QUEUE_WIDTH_POOL是全局并行隊列的堕油,它比普通并行隊列的最大并行數(shù)大潘飘。
- 創(chuàng)建并初始化隊列完成之后設置label和優(yōu)先級等其他信息肮之,之后包裝一下然后就返回了:
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;
return _dispatch_trace_queue_create(dq)._dq;
- 主隊列的創(chuàng)建
主隊列的是在程序啟動的時候就被系統(tǒng)主動創(chuàng)建的,具體是在libdispatch_init
方法里面被創(chuàng)建的卜录,在main函數(shù)調(diào)用之前就創(chuàng)建了(點擊了解iOS程序啟動流程):
//設置隊列
_dispatch_queue_set_current(&_dispatch_main_q);
//綁定主線程
_dispatch_queue_set_bound_thread(&_dispatch_main_q);
_dispatch_main_q是主隊列的底層結構戈擒,它的結構體_dispatch_main_q數(shù)據(jù)結構如下:
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,
};
這里我們可以看到主線程的最大并行數(shù)width為1,也就是串行艰毒。而且主隊列的序號dq_serialnum為1筐高。
- 全局并行隊列的創(chuàng)建
全局隊列也是由系統(tǒng)創(chuàng)建的,它是一個集合丑瞧。我們只能通過dispatch_get_global_queue()函數(shù)獲取柑土,而且只能獲取對應的優(yōu)先級的,如果我們隨便傳一個優(yōu)先級绊汹,獲取的queue就有可能為空稽屏。以下是demo演示:
dispatch_queue_t globQueue0 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t globQueue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t globQueue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_queue_t globQueue3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_queue_t customGlobQueue = dispatch_get_global_queue(1, 0);
NSLog(@"\n-globQueue0:%@\n-globQueue1:%@\n-globQueue2:%@\n-globQueue3:%@\n-customGlobQueue:%@",globQueue0,globQueue1,globQueue2,globQueue3,customGlobQueue);
demo打印結果是:
-globQueue0:<OS_dispatch_queue_global: com.apple.root.default-qos>
-globQueue1:<OS_dispatch_queue_global: com.apple.root.utility-qos>
-globQueue2:<OS_dispatch_queue_global: com.apple.root.user-initiated-qos>
-globQueue3:<OS_dispatch_queue_global: com.apple.root.background-qos>
-customGlobQueue:(null)
當我們傳入優(yōu)先級設置為1時,這時候它就找不到對應的隊列西乖,說明沒有優(yōu)先級為1的隊列狐榔,所以這個值還是不要隨便傳。我們平時用的最多的是默認default=0優(yōu)先級的隊列获雕,它的label是com.apple.root.default-qos薄腻,通過這個label我們到libdispatch庫里面搜索源碼:
struct dispatch_queue_global_s _dispatch_root_queues[] = {
#define _DISPATCH_ROOT_QUEUE_IDX(n, flags) \
((flags & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) ? \
DISPATCH_ROOT_QUEUE_IDX_##n##_QOS_OVERCOMMIT : \
DISPATCH_ROOT_QUEUE_IDX_##n##_QOS)
#define _DISPATCH_ROOT_QUEUE_ENTRY(n, flags, ...) \
[_DISPATCH_ROOT_QUEUE_IDX(n, flags)] = { \
DISPATCH_GLOBAL_OBJECT_HEADER(queue_global), \
.dq_state = DISPATCH_ROOT_QUEUE_STATE_INIT_VALUE, \
.do_ctxt = _dispatch_root_queue_ctxt(_DISPATCH_ROOT_QUEUE_IDX(n, flags)), \
.dq_atomic_flags = DQF_WIDTH(DISPATCH_QUEUE_WIDTH_POOL), \
.dq_priority = flags | ((flags & DISPATCH_PRIORITY_FLAG_FALLBACK) ? \
_dispatch_priority_make_fallback(DISPATCH_QOS_##n) : \
_dispatch_priority_make(DISPATCH_QOS_##n, 0)), \
__VA_ARGS__ \
}
_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, 0,
.dq_label = "com.apple.root.maintenance-qos",
.dq_serialnum = 4,
),
_DISPATCH_ROOT_QUEUE_ENTRY(MAINTENANCE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.maintenance-qos.overcommit",
.dq_serialnum = 5,
),
_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, 0,
.dq_label = "com.apple.root.background-qos",
.dq_serialnum = 6,
),
_DISPATCH_ROOT_QUEUE_ENTRY(BACKGROUND, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.background-qos.overcommit",
.dq_serialnum = 7,
),
_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, 0,
.dq_label = "com.apple.root.utility-qos",
.dq_serialnum = 8,
),
_DISPATCH_ROOT_QUEUE_ENTRY(UTILITY, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.utility-qos.overcommit",
.dq_serialnum = 9,
),
_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT, DISPATCH_PRIORITY_FLAG_FALLBACK,
.dq_label = "com.apple.root.default-qos",
.dq_serialnum = 10,
),
_DISPATCH_ROOT_QUEUE_ENTRY(DEFAULT,
DISPATCH_PRIORITY_FLAG_FALLBACK | DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.default-qos.overcommit",
.dq_serialnum = 11,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, 0,
.dq_label = "com.apple.root.user-initiated-qos",
.dq_serialnum = 12,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INITIATED, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.user-initiated-qos.overcommit",
.dq_serialnum = 13,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, 0,
.dq_label = "com.apple.root.user-interactive-qos",
.dq_serialnum = 14,
),
_DISPATCH_ROOT_QUEUE_ENTRY(USER_INTERACTIVE, DISPATCH_PRIORITY_FLAG_OVERCOMMIT,
.dq_label = "com.apple.root.user-interactive-qos.overcommit",
.dq_serialnum = 15,
),
};
這里可以看出,全局并行隊列是一個集合届案。它們都是由系統(tǒng)創(chuàng)建的庵楷,它是個單利,所以要用dispatch_once_f函數(shù)來創(chuàng)建萝玷。:
static inline void
_dispatch_root_queues_init(void)
{
dispatch_once_f(&_dispatch_root_queues_pred, NULL,
_dispatch_root_queues_init_once);
}
在函數(shù)_dispatch_root_queues_init_once中進行初始化:
static void
_dispatch_root_queues_init_once(void *context DISPATCH_UNUSED)
{
_dispatch_fork_becomes_unsafe();
#if DISPATCH_USE_INTERNAL_WORKQUEUE
size_t i;
for (i = 0; i < DISPATCH_ROOT_QUEUE_COUNT; i++) {
_dispatch_root_queue_init_pthread_pool(&_dispatch_root_queues[i], 0,
_dispatch_root_queues[i].dq_priority);
}
#else
int wq_supported = _pthread_workqueue_supported();
int r = ENOTSUP;
if (!(wq_supported & WORKQ_FEATURE_MAINTENANCE)) {
DISPATCH_INTERNAL_CRASH(wq_supported,
"QoS Maintenance support required");
}
#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
};
#endif
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
if (unlikely(!_dispatch_kevent_workqueue_enabled)) {
#if DISPATCH_USE_KEVENT_SETUP
cfg.workq_cb = _dispatch_worker_thread2;
r = pthread_workqueue_setup(&cfg, sizeof(cfg));
#else
r = _pthread_workqueue_init(_dispatch_worker_thread2,
offsetof(struct dispatch_queue_s, dq_serialnum), 0);
#endif // DISPATCH_USE_KEVENT_SETUP
#if DISPATCH_USE_KEVENT_WORKLOOP
} else if (wq_supported & WORKQ_FEATURE_WORKLOOP) {
#if DISPATCH_USE_KEVENT_SETUP
cfg.workq_cb = _dispatch_worker_thread2;
cfg.kevent_cb = (pthread_workqueue_function_kevent_t) _dispatch_kevent_worker_thread;
cfg.workloop_cb = (pthread_workqueue_function_workloop_t) _dispatch_workloop_worker_thread;
r = pthread_workqueue_setup(&cfg, sizeof(cfg));
#else
r = _pthread_workqueue_init_with_workloop(_dispatch_worker_thread2,
(pthread_workqueue_function_kevent_t)
_dispatch_kevent_worker_thread,
(pthread_workqueue_function_workloop_t)
_dispatch_workloop_worker_thread,
offsetof(struct dispatch_queue_s, dq_serialnum), 0);
#endif // DISPATCH_USE_KEVENT_SETUP
#endif // DISPATCH_USE_KEVENT_WORKLOOP
#if DISPATCH_USE_KEVENT_WORKQUEUE
} else if (wq_supported & WORKQ_FEATURE_KEVENT) {
#if DISPATCH_USE_KEVENT_SETUP
cfg.workq_cb = _dispatch_worker_thread2;
cfg.kevent_cb = (pthread_workqueue_function_kevent_t) _dispatch_kevent_worker_thread;
r = pthread_workqueue_setup(&cfg, sizeof(cfg));
#else
r = _pthread_workqueue_init_with_kevent(_dispatch_worker_thread2,
(pthread_workqueue_function_kevent_t)
_dispatch_kevent_worker_thread,
offsetof(struct dispatch_queue_s, dq_serialnum), 0);
#endif // DISPATCH_USE_KEVENT_SETUP
#endif
} else {
DISPATCH_INTERNAL_CRASH(wq_supported, "Missing Kevent WORKQ support");
}
#pragma clang diagnostic pop
if (r != 0) {
DISPATCH_INTERNAL_CRASH((r << 16) | wq_supported,
"Root queue initialization failed");
}
#endif // DISPATCH_USE_INTERNAL_WORKQUEUE
}
同步嫁乘、異步
在iOS中,隊列的調(diào)度主要由兩個函數(shù)dispatch_async()(異步)和dispatch_sync()(同步)球碉,它們負責將block添加到對應的隊列中蜓斧,然后在適當?shù)臅r候回調(diào)block。
異步函數(shù)-dispatch_async
異步函數(shù)dispatch_async的作用是可以異步添加block到派發(fā)隊列中睁冬。簡單來說就是調(diào)用dispatch_async不會阻塞當前線程挎春,block添加到隊列中之后立即返回,不需要等到block執(zhí)行完成豆拨。使用示例:
dispatch_async(mainQueue, ^{
NSLog(@"1");
});
- 底層原理
通過底層源碼來分析dispatch_async的實現(xiàn)原理:
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);
}
創(chuàng)建一個任務包裝器直奋,用于接收并保存當前的任務塊block,通過函數(shù)式保存下來施禾,等到合適的時機調(diào)用:
DISPATCH_ALWAYS_INLINE
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)
{
void *ctxt = _dispatch_Block_copy(work);
dc_flags |= DC_FLAG_BLOCK | DC_FLAG_ALLOCATED;
if (unlikely(_dispatch_block_has_private_data(work))) {
dc->dc_flags = dc_flags;
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);
}
dispatch_function_t func = _dispatch_Block_invoke(work);
if (dc_flags & DC_FLAG_CONSUME) {
func = _dispatch_call_block_and_release;
}
return _dispatch_continuation_init_f(dc, dqu, ctxt, func, flags, dc_flags);
}
然后把任務包裝器添加到隊列中去脚线,然后立即返回:
DISPATCH_ALWAYS_INLINE
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會把block添加到對應的隊列之中,后面的流程 _dispatch_continuation_async -> dx_push(x, y, z) dx_vtable(x)->dq_push(x, y, z)弥搞,這里dq_push是一個函數(shù)指針:
#define DISPATCH_QUEUE_VTABLE_HEADER(x); \
DISPATCH_OBJECT_VTABLE_HEADER(x); \
void (*const dq_activate)(dispatch_queue_class_t); \
void (*const dq_wakeup)(dispatch_queue_class_t, dispatch_qos_t, \
dispatch_wakeup_flags_t); \
void (*const dq_push)(dispatch_queue_class_t, dispatch_object_t, \
dispatch_qos_t)
void (*const dq_push)是個函數(shù)指針邮绿,queue子類的實現(xiàn)不一樣渠旁,根據(jù)不同的子類函數(shù)實現(xiàn)不一樣。以下是幾個常用的queue的dq_push實現(xiàn)(源碼具體在init.c文件中):
DISPATCH_NOINLINE
static void
_dispatch_object_no_invoke(dispatch_object_t dou,
DISPATCH_UNUSED dispatch_invoke_context_t dic,
DISPATCH_UNUSED dispatch_invoke_flags_t flags)
{
DISPATCH_INTERNAL_CRASH(dx_type(dou._do), "do_invoke called");
}
/*
* Dispatch queue cluster
*/
DISPATCH_NOINLINE
static void
_dispatch_queue_no_activate(dispatch_queue_class_t dqu)
{
DISPATCH_INTERNAL_CRASH(dx_type(dqu._dq), "dq_activate called");
}
DISPATCH_VTABLE_INSTANCE(queue,
// This is the base class for queues, no objects of this type are made
.do_type = _DISPATCH_QUEUE_CLUSTER,
.do_dispose = _dispatch_object_no_dispose,
.do_debug = _dispatch_queue_debug,
.do_invoke = _dispatch_object_no_invoke,
.dq_activate = _dispatch_queue_no_activate,
);
DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_serial, lane,
.do_type = DISPATCH_QUEUE_SERIAL_TYPE,
.do_dispose = _dispatch_lane_dispose,
.do_debug = _dispatch_queue_debug,
.do_invoke = _dispatch_lane_invoke,
.dq_activate = _dispatch_lane_activate,
.dq_wakeup = _dispatch_lane_wakeup,
.dq_push = _dispatch_lane_push,
);
DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_concurrent, lane,
.do_type = DISPATCH_QUEUE_CONCURRENT_TYPE,
.do_dispose = _dispatch_lane_dispose,
.do_debug = _dispatch_queue_debug,
.do_invoke = _dispatch_lane_invoke,
.dq_activate = _dispatch_lane_activate,
.dq_wakeup = _dispatch_lane_wakeup,
.dq_push = _dispatch_lane_concurrent_push,
);
DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_global, lane,
.do_type = DISPATCH_QUEUE_GLOBAL_ROOT_TYPE,
.do_dispose = _dispatch_object_no_dispose,
.do_debug = _dispatch_queue_debug,
.do_invoke = _dispatch_object_no_invoke,
.dq_activate = _dispatch_queue_no_activate,
.dq_wakeup = _dispatch_root_queue_wakeup,
.dq_push = _dispatch_root_queue_push,
);
DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_main, lane,
.do_type = DISPATCH_QUEUE_MAIN_TYPE,
.do_dispose = _dispatch_lane_dispose,
.do_debug = _dispatch_queue_debug,
.do_invoke = _dispatch_lane_invoke,
.dq_activate = _dispatch_queue_no_activate,
.dq_wakeup = _dispatch_main_queue_wakeup,
.dq_push = _dispatch_main_queue_push,
);
這里我們看到dq_push函數(shù)每個子類是不一樣的船逮。后面會分別分析顾腊。
備注:異步函數(shù)具有開啟新的線程的能力,但是不一定會開啟新的線程挖胃,比如異步函數(shù)執(zhí)行主隊列:
dispatch_async(mainQueue, ^{
NSLog(@"1");
});
上面的demo時不會開啟新的線程的杂靶,因為主隊列只能在主線程執(zhí)行。
同步函數(shù)-dispatch_sync
同步函數(shù)dispatch_sync的作用是可以同步添加block到派發(fā)隊列中酱鸭。簡單來說就是調(diào)用dispatch_sync會阻塞當前線程吗垮,block添加到隊列中之后不會立即返回,而是需要等到block執(zhí)行完成才能返回凹髓,并繼續(xù)執(zhí)行后面的代碼抱既。
- 使用示例:
dispatch_async(queue, ^{
NSLog(@"1");
});
- 調(diào)用流程
dispatch_sync->_dispatch_sync_f -> _dispatch_sync_f_inline->
DISPATCH_ALWAYS_INLINE
static inline void
_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);
}
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))) {
return _dispatch_sync_f_slow(dl, ctxt, func, 0, dl, dc_flags);
}
if (unlikely(dq->do_targetq->do_targetq)) {
return _dispatch_sync_recurse(dl, ctxt, func, dc_flags);
}
_dispatch_introspection_sync_begin(dl);
_dispatch_sync_invoke_and_complete(dl, ctxt, func DISPATCH_TRACE_ARG(
_dispatch_trace_item_sync_push_pop(dq, ctxt, func, dc_flags)));
}
到這里的話會根據(jù)不同的隊列類型進行調(diào)用,比如說會區(qū)分是串行隊列扁誓、或者是并行隊列。這個在后面的同步串行和同步并行部分繼續(xù)分析蚀之。
備注:同步會阻塞當前線程蝗敢,但不一定在當前線程執(zhí)行隊列任務,比如下面的代碼:
dispatch_queue_t conque1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"1");
dispatch_async(conque1, ^{
NSLog(@"2");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"3");
});
});
NSLog(@"4");
上面代碼中足删,在子線程同步執(zhí)行主隊列寿谴,主隊列會交給主線線程執(zhí)行,執(zhí)行完block之后再回到當前子線程執(zhí)行下面的代碼失受。
隊列讶泰、函數(shù)和線程的關系
有了隊列串行和并行,函數(shù)的同步異步拂到,我們就可以把它們之間的使用組合總結為同步串行痪署、同步并行、異步串行和異步并行兄旬。但是由于前面說過的主隊列和全局并行隊列的特殊性狼犯,在使用上還要細分,接下來一個個分析领铐。
同步串行
代碼示例:
- (void)serialSyncTest{
//創(chuàng)建串行隊列
dispatch_queue_t queue = dispatch_queue_create("com.hello-world.dongjianxiong", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
dispatch_sync(queue, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"2");
});
NSLog(@"3");
}
這段代碼的執(zhí)行流程是1 -> 2 -> 3悯森。
在這里dispatch_sync()調(diào)用流程是:
dispatch_sync
->_dispatch_sync_f
->_dispatch_sync_f_inline
->_dispatch_barrier_sync_f
->_dispatch_barrier_sync_f_inline
->_dispatch_lane_barrier_sync_invoke_and_complete
->_dispatch_sync_function_invoke_inline
:
- 在函數(shù)_dispatch_sync_f_inline()中判斷是否是串行隊列,這里是同步串行绪撵,所以走_dispatch_barrier_sync_f
if (likely(dq->dq_width == 1)) {
return _dispatch_barrier_sync_f(dq, ctxt, func, dc_flags);
}
- 函數(shù)
_dispatch_barrier_sync_f_inline
這里會嘗試獲取同步鎖瓢姻,判斷是繼續(xù)執(zhí)行,還是走_dispatch_sync_f_slow流程:
static inline void
_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;
// The more correct thing to do would be to merge the qos of the thread
// that just acquired the barrier lock into the queue state.
//
// However this is too expensive for the fast path, so skip doing it.
// The chosen tradeoff is that if an enqueue on a lower priority thread
// contends with this fast path, this thread may receive a useless override.
//
// 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_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)));
}
函數(shù)中嘗試獲得鎖(dispatch_queue_try_acquire_barrier_sync),如果獲取成功音诈,進入_dispatch_introspection_sync_begin(dl)對隊列進行調(diào)整幻碱,比如根據(jù)優(yōu)先級調(diào)整循序等绎狭。然后進行block調(diào)用:
_dispatch_lane_barrier_sync_invoke_and_complete
-> _dispatch_sync_function_invoke_inline
:
DISPATCH_ALWAYS_INLINE
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ù)_dispatch_sync_function_invoke_inline()中進行push隊列,然后在當前線程中調(diào)用block(_dispatch_client_callout)收班,調(diào)用完成之后然后pop出列坟岔。
- 死鎖的原因
如果前面獲取同步鎖失敗,則會進入_dispatch_sync_f_slow->DISPATCH_WAIT_FOR_QUEUE流程摔桦,在這里等待鎖的釋放社付。在這里會校驗當前的隊列和要同步的隊列是否同一個,如果是就拋出死鎖崩潰信息:
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");
}
- block調(diào)用
串行隊列:_dispatch_lane_barrier_sync_invoke_and_complete
->_dispatch_client_callout
主隊列由runloop調(diào)用:
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
->_dispatch_main_queue_callback_4CF
->_dispatch_client_callout
->_dispatch_async_and_wait_invoke
->_dispatch_client_callout
同步并行
代碼示例:
- (void)concurrentSyncTest{
//創(chuàng)建并行隊列
dispatch_queue_t queue = dispatch_queue_create("com.hello-world.dongjianxiong", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_sync(queue, ^{
NSLog(@"%d-%@",i,[NSThread currentThread]);
NSLog(@"2");
});
NSLog(@"3");
}
代碼執(zhí)行順序:1->2->3邻耕,與同步串行一樣鸥咖。
- 普通隊列同步并行dispatch_sync()調(diào)用流程是:
dispatch_sync
->_dispatch_sync_f
->_dispatch_sync_f_inline
->_dispatch_sync_invoke_and_complete
->_dispatch_sync_function_invoke_inline
- 全局隊列同步并行dispatch_sync()調(diào)用流程是
代碼示例:
- (void)globalSyncTest{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
NSLog(@"1");
dispatch_sync(queue, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"2");
});
NSLog(@"3");
}
dispatch_sync
->_dispatch_sync_f
->_dispatch_sync_f_inline
->_dispatch_sync_f_slow
->__DISPATCH_WAIT_FOR_QUEUE__
->dx_push
globalQueue會交由dx_push添加到隊列中,然后等待系統(tǒng)線程池分配線程執(zhí)行block兄世。
- block 調(diào)用
同步并行:_dispatch_sync_invoke_and_complete
->_dispatch_client_callout
全局同步并行:_dispatch_sync_function_invoke
->_dispatch_client_callout
異步串行
代碼示例:
- (void)serialAsyncTest{
//創(chuàng)建串行隊列
dispatch_queue_t queue = dispatch_queue_create("com.hello-world.dongjianxiong", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"2");
});
NSLog(@"3");
}
代碼執(zhí)行順序:1->3->2啼辣。這里的block不會阻塞3的執(zhí)行,它可能在新的線程執(zhí)行的御滩,也可能不是鸥拧。
dispatch_async()調(diào)用流程:
dispatch_async
->_dispatch_continuation_async
->dx_push(x, y, z) dx_vtable(x)
->dq_push(x, y, z)
:
DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_serial, lane,
.do_type = DISPATCH_QUEUE_SERIAL_TYPE,
.do_dispose = _dispatch_lane_dispose,
.do_debug = _dispatch_queue_debug,
.do_invoke = _dispatch_lane_invoke,
.dq_activate = _dispatch_lane_activate,
.dq_wakeup = _dispatch_lane_wakeup,
.dq_push = _dispatch_lane_push,
);
DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_main, lane,
.do_type = DISPATCH_QUEUE_MAIN_TYPE,
.do_dispose = _dispatch_lane_dispose,
.do_debug = _dispatch_queue_debug,
.do_invoke = _dispatch_lane_invoke,
.dq_activate = _dispatch_queue_no_activate,
.dq_wakeup = _dispatch_main_queue_wakeup,
.dq_push = _dispatch_main_queue_push,
);
普通串行隊列_dispatch_lane_push(dq_push)
->dx_wakeup(x, y, z) dx_vtable(x)
->_dispatch_lane_wakeup(dq_wakeup)
->_dispatch_queue_wakeup
->
主隊列:_dispatch_lane_push(dq_push)->
dx_wakeup(x, y, z) dx_vtable(x)->
_dispatch_main_queue_wakeup(dq_wakeup)->
_dispatch_runloop_queue_wakeup`
void
_dispatch_main_queue_wakeup(dispatch_queue_main_t dq, dispatch_qos_t qos,
dispatch_wakeup_flags_t flags)
{
#if DISPATCH_COCOA_COMPAT
if (_dispatch_queue_is_thread_bound(dq)) {
return _dispatch_runloop_queue_wakeup(dq->_as_dl, qos, flags);
}
#endif
return _dispatch_lane_wakeup(dq, qos, flags);
}
由于全局隊列綁定到主線程,所以任務會被添加到runloop中削解,等待runloop調(diào)用富弦。
- block調(diào)用
串行隊列:_dispatch_workloop_worker_thread
->_dispatch_lane_invoke
->_dispatch_lane_serial_drain
->_dispatch_client_callout
->_dispatch_call_block_and_release
主隊列由runloop調(diào)用:
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
->_dispatch_main_queue_callback_4CF
->_dispatch_client_callout
->_dispatch_call_block_and_release
異步并行
代碼示例:
- (void)concurrentAsyncTest{
//創(chuàng)建并行隊列
// dispatch_queue_t queue = dispatch_queue_create("com.hello-world.dongjianxiong", DISPATCH_QUEUE_CONCURRENT);
//創(chuàng)建全局并行隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
NSLog(@"%@",[NSThread currentThread]);
});
NSLog(@"3");
}
代碼執(zhí)行流程:1->3->2。這里的block不會阻塞3的執(zhí)行氛驮,它可能在新的線程執(zhí)行的腕柜,也可能不是。
dispatch_async()調(diào)用流程:
dispatch_async
->_dispatch_continuation_async
->dx_push(x, y, z) dx_vtable(x)
->dq_push(x, y, z)
:
DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_concurrent, lane,
.do_type = DISPATCH_QUEUE_CONCURRENT_TYPE,
.do_dispose = _dispatch_lane_dispose,
.do_debug = _dispatch_queue_debug,
.do_invoke = _dispatch_lane_invoke,
.dq_activate = _dispatch_lane_activate,
.dq_wakeup = _dispatch_lane_wakeup,
.dq_push = _dispatch_lane_concurrent_push,
);
DISPATCH_VTABLE_SUBCLASS_INSTANCE(queue_global, lane,
.do_type = DISPATCH_QUEUE_GLOBAL_ROOT_TYPE,
.do_dispose = _dispatch_object_no_dispose,
.do_debug = _dispatch_queue_debug,
.do_invoke = _dispatch_object_no_invoke,
.dq_activate = _dispatch_queue_no_activate,
.dq_wakeup = _dispatch_root_queue_wakeup,
.dq_push = _dispatch_root_queue_push,
);
對于全局并行隊列矫废,dq_push = _dispatch_root_queue_push盏缤, _dispatch_root_queue_push的流程:
_dispatch_root_queue_push_inline
->_dispatch_root_queue_push
->_dispatch_root_queue_poke
->_dispatch_root_queue_poke_slow
。
全局并行隊列流程會在_dispatch_root_queue_poke_slow()函數(shù)中選擇一個線程來執(zhí)行當前的block蓖扑,如果線程池的線程不夠用唉铜,則創(chuàng)建新的線程。同時第一次進來會對全局變量進行初始化:
_dispatch_root_queues_init();
- block 調(diào)用
并行隊列:_dispatch_worker_thread2
->_dispatch_root_queue_drain
->_dispatch_async_redirect_invoke
->_dispatch_continuation_pop
->_dispatch_client_callout
->_dispatch_call_block_and_release
全局并行隊列:_dispatch_worker_thread2
->_dispatch_root_queue_drain
->_dispatch_queue_override_invoke
->_dispatch_client_callout
->_dispatch_call_block_and_release
赵誓。