GCD 全稱是 Grand Central Dispatch, 純 C 語言,提供了很是多強大的函數程序員
使用例子bash
- (void)syncTest{ // 任務 隊列 函數 dispatch_block_t block = ^{ NSLog(@"hello word"); }; dispatch_queue_t queue = dispatch_queue_create("com.janice.cn", NULL); dispatch_async(queue, block); } 複製代碼
以上即是將任務添加到隊列,而且指定執行任務的函數markdown
詳解:多線程
串行隊列併發
一次只能執行一個,上一個任務沒有執行完,就沒法繼續執行下一個任務,也就是效率比較低,任務耗時較長,DISPATCH_QUEUE_SERIAL。app
並行隊列異步
併發隊列會開啓多個線程來執行任務,因此能夠同時執行多個任務,任務執行的順序也不會固定,DISPATCH_QUEUE_CONCURRENT。練習一async
- (void)textDemo{ dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_CONCURRENT); NSLog(@"1"); dispatch_async(queue, ^{ NSLog(@"2"); dispatch_async(queue, ^{ NSLog(@"3"); }); NSLog(@"4"); }); NSLog(@"5"); } 複製代碼
執行順序:1,5,2,4,3函數
練習二oop
- (void)wbinterDemo{ dispatch_queue_t queue = dispatch_queue_create("com.lg.cooci.cn", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ NSLog(@"1"); }); dispatch_async(queue, ^{ NSLog(@"2"); }); // 堵塞 - 護犢子 dispatch_sync(queue, ^{ NSLog(@"3"); }); // ********************** NSLog(@"0"); dispatch_async(queue, ^{ NSLog(@"7"); }); dispatch_async(queue, ^{ NSLog(@"8"); }); dispatch_async(queue, ^{ NSLog(@"9"); }); } 複製代碼
A: 1230789 B: 1237890 C: 3120798 D: 2137890
正確答案:A、C
練習三
- (void)textDemo2{ // 串行隊列 dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_SERIAL); NSLog(@"1"); // 異步函數 dispatch_async(queue, ^{ NSLog(@"2"); dispatch_sync(queue, ^{ NSLog(@"3"); }); NSLog(@"4"); }); NSLog(@"5"); } 複製代碼
中間執行任務隊列示意圖:
說明:
執行流程
練習四
- (void)textDemo3{ // 串行隊列 dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_SERIAL); NSLog(@"1"); // 異步函數 dispatch_async(queue, ^{ NSLog(@"2"); NSLog(@"4"); dispatch_sync(queue, ^{ NSLog(@"3"); }); }); NSLog(@"5"); } 複製代碼
打印結果:
練習四在練習三的基礎上作了一丟丟改變,將打印 4 任務放在同步函數塊的前面,再來分析一下
中間執行任務隊列示意圖:
說明:
執行流程
打印結果:
**總結:**練習3、練習四 ,若是異步函數裏面嵌同步函數,就會發生死鎖!!!。
dispatch_queue_create 是如何建立的?
就須要去探索隊列建立的源碼
獲取地址:連接:pan.baidu.com/s/1Avpzm947… 提取碼:l8ci
因此在探索源碼的時候咱們也看下源碼是怎麼區分的
_dispatch_lane_create_with_target 源碼
DISPATCH_NOINLINE static dispatch_queue_t _dispatch_lane_create_with_target(const char *label, dispatch_queue_attr_t dqa, dispatch_queue_t tq, bool legacy) { dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa); // // Step 1: Normalize arguments (qos, overcommit, tq) // dispatch_qos_t qos = dqai.dqai_qos; #if !HAVE_PTHREAD_WORKQUEUE_QOS if (qos == DISPATCH_QOS_USER_INTERACTIVE) { dqai.dqai_qos = qos = DISPATCH_QOS_USER_INITIATED; } if (qos == DISPATCH_QOS_MAINTENANCE) { dqai.dqai_qos = qos = DISPATCH_QOS_BACKGROUND; } #endif // !HAVE_PTHREAD_WORKQUEUE_QOS _dispatch_queue_attr_overcommit_t overcommit = dqai.dqai_overcommit; if (overcommit != _dispatch_queue_attr_overcommit_unspecified && tq) { if (tq->do_targetq) { DISPATCH_CLIENT_CRASH(tq, "Cannot specify both overcommit and " "a non-global target queue"); } } if (tq && dx_type(tq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE) { // Handle discrepancies between attr and target queue, attributes win if (overcommit == _dispatch_queue_attr_overcommit_unspecified) { if (tq->dq_priority & DISPATCH_PRIORITY_FLAG_OVERCOMMIT) { overcommit = _dispatch_queue_attr_overcommit_enabled; } else { overcommit = _dispatch_queue_attr_overcommit_disabled; } } if (qos == DISPATCH_QOS_UNSPECIFIED) { qos = _dispatch_priority_qos(tq->dq_priority); } tq = NULL; } else if (tq && !tq->do_targetq) { // target is a pthread or runloop root queue, setting QoS or overcommit // is disallowed if (overcommit != _dispatch_queue_attr_overcommit_unspecified) { DISPATCH_CLIENT_CRASH(tq, "Cannot specify an overcommit attribute " "and use this kind of target queue"); } } else { if (overcommit == _dispatch_queue_attr_overcommit_unspecified) { // Serial queues default to overcommit! overcommit = dqai.dqai_concurrent ? _dispatch_queue_attr_overcommit_disabled : _dispatch_queue_attr_overcommit_enabled; } } if (!tq) { tq = _dispatch_get_root_queue( qos == DISPATCH_QOS_UNSPECIFIED ? DISPATCH_QOS_DEFAULT : qos, // 4 overcommit == _dispatch_queue_attr_overcommit_enabled)->_as_dq; // 0 1 if (unlikely(!tq)) { DISPATCH_CLIENT_CRASH(qos, "Invalid queue attribute"); } } // // 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; if (dqai.dqai_concurrent) { // 經過dqai.dqai_concurrent 來區分併發和串行 // OS_dispatch_queue_concurrent_class 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; } } // 開闢內存 - 生成響應的對象 queue 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 == _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; } 複製代碼
外面傳進來的隊列類型參數爲dpa,因而看下這段代碼
看到有個判斷,若是 dpa 爲空,就直接返回 dqai,前面有貼出,當 串行隊列 DISPATCH_QUEUE_SERIAL 的時候的定義就是爲空 ,不然作其餘處理,返回
建立關鍵步驟:
第一步初始化並分配內存空間
構造方法
1)第一個參數 dq 對象
2)dqai.dqai_concurrent 第三參數,若是爲併發隊列便標識,傳 DISPATCH_QUEUE_WIDTH_MAX,不然 1.
overcommit 的賦值
dq->do_targetq = tq;
複製代碼
打印獲取到的主隊列和全局併發隊列,由於是全局靜態結構體
主隊列結構體
全局隊列屬性打印
經過打印可知,全局變量的 width = 0xfff,上面有打印併發隊列的 width = 0xfffe
隊列結構體
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, ), }; 複製代碼
出來 main queue 其餘指針都是由 root queue 模板建立的
dispatch_object_t
typedef struct dispatch_object_s {
private:
dispatch_object_s();
~dispatch_object_s();
dispatch_object_s(const dispatch_object_s &);
void operator=(const dispatch_object_s &);
} *dispatch_object_t;
複製代碼