用示例阐明 GCD 的同步异步串行并行

用示例阐明 GCD 的同步异步串行并行

[TOC]

示例

  1. 下文示例中所用到的宏定义有:

    GCD_TEST_LOG(task)

    NSLog(@"task:%@ main:%@ p:%p", task, NSThread.isMainThread ? @"1" : @"0", NSThread.currentThread)
    

    GCD_TEST_TASK_A

    GCD_TEST_LOG(@"A");
    NSLog(@"1");
    [NSThread sleepForTimeInterval:1.f];
    NSLog(@"2")
    

    GCD_TEST_TASK_B

    GCD_TEST_LOG(@"B");
    NSLog(@"4");
    [NSThread sleepForTimeInterval:1.f];
    NSLog(@"5")
    

    GCD_TEST_TASK_C

    GCD_TEST_LOG(@"C");
    NSLog(@"7");
    [NSThread sleepForTimeInterval:1.f];
    NSLog(@"8")
    

    GCD_TEST_TASK_D

    GCD_TEST_LOG(@"D");
    NSLog(@"10");
    [NSThread sleepForTimeInterval:1.f];
    NSLog(@"11")
    
  2. 下文示例代码在主线程中执行.

  3. 下文所用符号示意:

    ✅ 较常用.

    ⚠️ 极少使用, 或使用有风险, 或使用无意义.

  4. 为方便复制调试, 以上宏定义源码如下:

    #define GCD_TEST_LOG(task) NSLog(@"task:%@ main:%@ p:%p", task, NSThread.isMainThread ? @"1" : @"0", NSThread.currentThread)
    
    #define GCD_TEST_TASK_A \
    GCD_TEST_LOG(@"A"); \
    NSLog(@"1"); \
    [NSThread sleepForTimeInterval:1.f]; \
    NSLog(@"2")
    
    #define GCD_TEST_TASK_B \
    GCD_TEST_LOG(@"B"); \
    NSLog(@"4"); \
    [NSThread sleepForTimeInterval:1.f]; \
    NSLog(@"5")
    
    #define GCD_TEST_TASK_C \
    GCD_TEST_LOG(@"C"); \
    NSLog(@"7"); \
    [NSThread sleepForTimeInterval:1.f]; \
    NSLog(@"8")
    
    #define GCD_TEST_TASK_D \
    GCD_TEST_LOG(@"D"); \
    NSLog(@"10"); \
    [NSThread sleepForTimeInterval:1.f]; \
    NSLog(@"11")
    

main_queue

dispatch_sync ⚠️

dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_sync(main_queue, ^{ GCD_TEST_TASK_A; });       // 1 | 2
NSLog(@"3");                                            // 3
dispatch_sync(main_queue, ^{ GCD_TEST_TASK_B; });       // 4 | 5
NSLog(@"6");                                            // 6
dispatch_sync(main_queue, ^{ GCD_TEST_TASK_C; });       // 7 | 8
NSLog(@"9");                                            // 9
dispatch_sync(main_queue, ^{ GCD_TEST_TASK_D; });       // 10 | 11
NSLog(@"12");                                           // 12

输出

崩溃在第 2 行

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

如在其它线程执行以上代码, 则正常执行. 如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_queue_t main_queue = dispatch_get_main_queue();
    dispatch_sync(main_queue, ^{ GCD_TEST_TASK_A; });       // 1 | 2
    NSLog(@"3");                                            // 3
    dispatch_sync(main_queue, ^{ GCD_TEST_TASK_B; });       // 4 | 5
    NSLog(@"6");                                            // 6
    dispatch_sync(main_queue, ^{ GCD_TEST_TASK_C; });       // 7 | 8
    NSLog(@"9");                                            // 9
    dispatch_sync(main_queue, ^{ GCD_TEST_TASK_D; });       // 10 | 11
    NSLog(@"12");                                           // 12
});

输出

2017-02-11 17:59:28.471943+0800 sun[68420:10866547] task:A main:1 p:0x600001449f40
2017-02-11 17:59:28.472160+0800 sun[68420:10866547] 1
2017-02-11 17:59:29.472686+0800 sun[68420:10866547] 2
2017-02-11 17:59:29.472918+0800 sun[68420:10866746] 3
2017-02-11 17:59:29.474518+0800 sun[68420:10866547] task:B main:1 p:0x600001449f40
2017-02-11 17:59:29.474743+0800 sun[68420:10866547] 4
2017-02-11 17:59:30.475987+0800 sun[68420:10866547] 5
2017-02-11 17:59:30.476268+0800 sun[68420:10866746] 6
2017-02-11 17:59:30.476631+0800 sun[68420:10866547] task:C main:1 p:0x600001449f40
2017-02-11 17:59:30.476804+0800 sun[68420:10866547] 7
2017-02-11 17:59:31.478109+0800 sun[68420:10866547] 8
2017-02-11 17:59:31.478349+0800 sun[68420:10866746] 9
2017-02-11 17:59:31.478600+0800 sun[68420:10866547] task:D main:1 p:0x600001449f40
2017-02-11 17:59:31.478784+0800 sun[68420:10866547] 10
2017-02-11 17:59:32.480031+0800 sun[68420:10866547] 11
2017-02-11 17:59:32.480304+0800 sun[68420:10866746] 12

dispatch_async ✅

dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_async(main_queue, ^{ GCD_TEST_TASK_A; });      // 1 | 2
NSLog(@"3");                                            // 3
dispatch_async(main_queue, ^{ GCD_TEST_TASK_B; });      // 4 | 5
NSLog(@"6");                                            // 6
dispatch_async(main_queue, ^{ GCD_TEST_TASK_C; });      // 7 | 8
NSLog(@"9");                                            // 9
dispatch_async(main_queue, ^{ GCD_TEST_TASK_D; });      // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:00:19.191572+0800 sun[68464:10868282] 3
2017-02-11 18:00:19.191773+0800 sun[68464:10868282] 6
2017-02-11 18:00:19.191927+0800 sun[68464:10868282] 9
2017-02-11 18:00:19.192077+0800 sun[68464:10868282] 12
2017-02-11 18:00:19.192433+0800 sun[68464:10868282] task:A main:1 p:0x6000028cdf40
2017-02-11 18:00:19.192569+0800 sun[68464:10868282] 1
2017-02-11 18:00:20.193589+0800 sun[68464:10868282] 2
2017-02-11 18:00:20.193928+0800 sun[68464:10868282] task:B main:1 p:0x6000028cdf40
2017-02-11 18:00:20.194083+0800 sun[68464:10868282] 4
2017-02-11 18:00:21.194587+0800 sun[68464:10868282] 5
2017-02-11 18:00:21.194946+0800 sun[68464:10868282] task:C main:1 p:0x6000028cdf40
2017-02-11 18:00:21.195064+0800 sun[68464:10868282] 7
2017-02-11 18:00:22.195342+0800 sun[68464:10868282] 8
2017-02-11 18:00:22.195688+0800 sun[68464:10868282] task:D main:1 p:0x6000028cdf40
2017-02-11 18:00:22.195850+0800 sun[68464:10868282] 10
2017-02-11 18:00:23.197078+0800 sun[68464:10868282] 11

global_queue

dispatch_sync ⚠️

dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(global_queue, ^{ GCD_TEST_TASK_A; });     // 1 | 2
NSLog(@"3");                                            // 3
dispatch_sync(global_queue, ^{ GCD_TEST_TASK_B; });     // 4 | 5
NSLog(@"6");                                            // 6
dispatch_sync(global_queue, ^{ GCD_TEST_TASK_C; });     // 7 | 8
NSLog(@"9");                                            // 9
dispatch_sync(global_queue, ^{ GCD_TEST_TASK_D; });     // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:01:21.071692+0800 sun[68510:10869926] task:A main:1 p:0x600002912a40
2017-02-11 18:01:21.071854+0800 sun[68510:10869926] 1
2017-02-11 18:01:22.073179+0800 sun[68510:10869926] 2
2017-02-11 18:01:22.073418+0800 sun[68510:10869926] 3
2017-02-11 18:01:22.073596+0800 sun[68510:10869926] task:B main:1 p:0x600002912a40
2017-02-11 18:01:22.073717+0800 sun[68510:10869926] 4
2017-02-11 18:01:23.074995+0800 sun[68510:10869926] 5
2017-02-11 18:01:23.075236+0800 sun[68510:10869926] 6
2017-02-11 18:01:23.075391+0800 sun[68510:10869926] task:C main:1 p:0x600002912a40
2017-02-11 18:01:23.075554+0800 sun[68510:10869926] 7
2017-02-11 18:01:24.076513+0800 sun[68510:10869926] 8
2017-02-11 18:01:24.076904+0800 sun[68510:10869926] 9
2017-02-11 18:01:24.077053+0800 sun[68510:10869926] task:D main:1 p:0x600002912a40
2017-02-11 18:01:24.077247+0800 sun[68510:10869926] 10
2017-02-11 18:01:25.078505+0800 sun[68510:10869926] 11
2017-02-11 18:01:25.078753+0800 sun[68510:10869926] 12

dispatch_async ✅

dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(global_queue, ^{ GCD_TEST_TASK_A; });    // 1 | 2
NSLog(@"3");                                            // 3
dispatch_async(global_queue, ^{ GCD_TEST_TASK_B; });    // 4 | 5
NSLog(@"6");                                            // 6
dispatch_async(global_queue, ^{ GCD_TEST_TASK_C; });    // 7 | 8
NSLog(@"9");                                            // 9
dispatch_async(global_queue, ^{ GCD_TEST_TASK_D; });    // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:02:06.159847+0800 sun[68554:10871641] 3
2017-02-11 18:02:06.159892+0800 sun[68554:10871805] task:A main:0 p:0x60000163a2c0
2017-02-11 18:02:06.160052+0800 sun[68554:10871641] 6
2017-02-11 18:02:06.160065+0800 sun[68554:10871805] 1
2017-02-11 18:02:06.160098+0800 sun[68554:10871784] task:B main:0 p:0x60000190ec80
2017-02-11 18:02:06.160241+0800 sun[68554:10871641] 9
2017-02-11 18:02:06.160247+0800 sun[68554:10871784] 4
2017-02-11 18:02:06.160263+0800 sun[68554:10871797] task:C main:0 p:0x600001639dc0
2017-02-11 18:02:06.160404+0800 sun[68554:10871641] 12
2017-02-11 18:02:06.160439+0800 sun[68554:10871787] task:D main:0 p:0x60000165e080
2017-02-11 18:02:06.161688+0800 sun[68554:10871787] 10
2017-02-11 18:02:06.161892+0800 sun[68554:10871797] 7
2017-02-11 18:02:07.160298+0800 sun[68554:10871805] 2
2017-02-11 18:02:07.160484+0800 sun[68554:10871784] 5
2017-02-11 18:02:07.166661+0800 sun[68554:10871787] 11
2017-02-11 18:02:07.166676+0800 sun[68554:10871797] 8

custom_queue

DISPATCH_QUEUE_SERIAL

dispatch_sync ⚠️
dispatch_queue_t custom_queue = dispatch_queue_create("custom_queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_A; });     // 1 | 2
NSLog(@"3");                                            // 3
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_B; });     // 4 | 5
NSLog(@"6");                                            // 6
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_C; });     // 7 | 8
NSLog(@"9");                                            // 9
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_D; });     // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:02:46.126540+0800 sun[68594:10873135] task:A main:1 p:0x600001657880
2017-02-11 18:02:46.126753+0800 sun[68594:10873135] 1
2017-02-11 18:02:47.128070+0800 sun[68594:10873135] 2
2017-02-11 18:02:47.128445+0800 sun[68594:10873135] 3
2017-02-11 18:02:47.128615+0800 sun[68594:10873135] task:B main:1 p:0x600001657880
2017-02-11 18:02:47.128740+0800 sun[68594:10873135] 4
2017-02-11 18:02:48.129982+0800 sun[68594:10873135] 5
2017-02-11 18:02:48.130324+0800 sun[68594:10873135] 6
2017-02-11 18:02:48.130498+0800 sun[68594:10873135] task:C main:1 p:0x600001657880
2017-02-11 18:02:48.130619+0800 sun[68594:10873135] 7
2017-02-11 18:02:49.131752+0800 sun[68594:10873135] 8
2017-02-11 18:02:49.131942+0800 sun[68594:10873135] 9
2017-02-11 18:02:49.132027+0800 sun[68594:10873135] task:D main:1 p:0x600001657880
2017-02-11 18:02:49.132119+0800 sun[68594:10873135] 10
2017-02-11 18:02:50.132608+0800 sun[68594:10873135] 11
2017-02-11 18:02:50.132791+0800 sun[68594:10873135] 12
dispatch_async ✅
dispatch_queue_t custom_queue = dispatch_queue_create("custom_queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_A; });    // 1 | 2
NSLog(@"3");                                            // 3
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_B; });    // 4 | 5
NSLog(@"6");                                            // 6
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_C; });    // 7 | 8
NSLog(@"9");                                            // 9
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_D; });    // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:03:31.083347+0800 sun[68633:10874631] 3
2017-02-11 18:03:31.083393+0800 sun[68633:10874809] task:A main:0 p:0x600000d71800
2017-02-11 18:03:31.083545+0800 sun[68633:10874631] 6
2017-02-11 18:03:31.083569+0800 sun[68633:10874809] 1
2017-02-11 18:03:31.083704+0800 sun[68633:10874631] 9
2017-02-11 18:03:31.083910+0800 sun[68633:10874631] 12
2017-02-11 18:03:32.085991+0800 sun[68633:10874809] 2
2017-02-11 18:03:32.086343+0800 sun[68633:10874809] task:B main:0 p:0x600000d71800
2017-02-11 18:03:32.086501+0800 sun[68633:10874809] 4
2017-02-11 18:03:33.087598+0800 sun[68633:10874809] 5
2017-02-11 18:03:33.087961+0800 sun[68633:10874809] task:C main:0 p:0x600000d71800
2017-02-11 18:03:33.088119+0800 sun[68633:10874809] 7
2017-02-11 18:03:34.091592+0800 sun[68633:10874809] 8
2017-02-11 18:03:34.091858+0800 sun[68633:10874809] task:D main:0 p:0x600000d71800
2017-02-11 18:03:34.092052+0800 sun[68633:10874809] 10
2017-02-11 18:03:35.096494+0800 sun[68633:10874809] 11

DISPATCH_QUEUE_CONCURRENT

dispatch_sync ⚠️

等效 global_queue | dispatch_sync

dispatch_queue_t custom_queue = dispatch_queue_create("custom_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_A; });     // 1 | 2
NSLog(@"3");                                            // 3
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_B; });     // 4 | 5
NSLog(@"6");                                            // 6
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_C; });     // 7 | 8
NSLog(@"9");                                            // 9
dispatch_sync(custom_queue, ^{ GCD_TEST_TASK_D; });     // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:04:13.914992+0800 sun[68678:10876152] task:A main:1 p:0x600000de6a80
2017-02-11 18:04:13.915168+0800 sun[68678:10876152] 1
2017-02-11 18:04:14.915620+0800 sun[68678:10876152] 2
2017-02-11 18:04:14.915822+0800 sun[68678:10876152] 3
2017-02-11 18:04:14.915926+0800 sun[68678:10876152] task:B main:1 p:0x600000de6a80
2017-02-11 18:04:14.916103+0800 sun[68678:10876152] 4
2017-02-11 18:04:15.916831+0800 sun[68678:10876152] 5
2017-02-11 18:04:15.917190+0800 sun[68678:10876152] 6
2017-02-11 18:04:15.917319+0800 sun[68678:10876152] task:C main:1 p:0x600000de6a80
2017-02-11 18:04:15.917427+0800 sun[68678:10876152] 7
2017-02-11 18:04:16.918675+0800 sun[68678:10876152] 8
2017-02-11 18:04:16.918918+0800 sun[68678:10876152] 9
2017-02-11 18:04:16.919083+0800 sun[68678:10876152] task:D main:1 p:0x600000de6a80
2017-02-11 18:04:16.919277+0800 sun[68678:10876152] 10
2017-02-11 18:04:17.920562+0800 sun[68678:10876152] 11
2017-02-11 18:04:17.920799+0800 sun[68678:10876152] 12
dispatch_async ✅

等效 global_queue| dispatch_async

dispatch_queue_t custom_queue = dispatch_queue_create("custom_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_A; });    // 1 | 2
NSLog(@"3");                                            // 3
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_B; });    // 4 | 5
NSLog(@"6");                                            // 6
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_C; });    // 7 | 8
NSLog(@"9");                                            // 9
dispatch_async(custom_queue, ^{ GCD_TEST_TASK_D; });    // 10 | 11
NSLog(@"12");                                           // 12

输出

2017-02-11 18:04:53.590727+0800 sun[68716:10877557] 3
2017-02-11 18:04:53.590749+0800 sun[68716:10877625] task:A main:0 p:0x6000022c4d80
2017-02-11 18:04:53.590956+0800 sun[68716:10877557] 6
2017-02-11 18:04:53.590976+0800 sun[68716:10877625] 1
2017-02-11 18:04:53.590980+0800 sun[68716:10877635] task:B main:0 p:0x6000022afd00
2017-02-11 18:04:53.591153+0800 sun[68716:10877557] 9
2017-02-11 18:04:53.591198+0800 sun[68716:10877639] task:C main:0 p:0x6000022b25c0
2017-02-11 18:04:53.591205+0800 sun[68716:10877635] 4
2017-02-11 18:04:53.591335+0800 sun[68716:10877557] 12
2017-02-11 18:04:53.591379+0800 sun[68716:10877639] 7
2017-02-11 18:04:53.591403+0800 sun[68716:10877641] task:D main:0 p:0x6000022c5c80
2017-02-11 18:04:53.592740+0800 sun[68716:10877641] 10
2017-02-11 18:04:54.593739+0800 sun[68716:10877625] 2
2017-02-11 18:04:54.593756+0800 sun[68716:10877639] 8
2017-02-11 18:04:54.593756+0800 sun[68716:10877635] 5
2017-02-11 18:04:54.593756+0800 sun[68716:10877641] 11

总结

总结只有一点, 个人认为这一点是理解 线程 上的 任务任务串行并行 的核心要点. 而 dispatch_syncdispatch_async 则是在某一 线程 下调度某一 线程队列 的行为, 其行为是 平行相对 的.

  1. dispatch_syncdispatch_async 都是相对当前线程, 死锁与否都是相对当前添加任务所在线程.

对于任务的串行并行, 无需再赘述.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342