About GCD group,barrier

关于GCD的理解,可以参看本博另一篇文章

GCD 串行并行/同步异步 理解

dispatch_barrier_async 实现顺序执行。

根据上一篇文章的理解,如果调用 dipatch_async,异步添加到并行队列中,应该是无法控制执行顺序的。
但是通过dipatch_barrier_async可以实现顺序操作。

dispatch_barrier 说明

使用dispatch_barrier将任务加入到并行队列之后,任务会在前面任务全部执行完成之后执行,任务执行过程中,其他任务无法执行,直到barrier任务执行完成


图片摘自小笨狼的漫谈GCD

代码

    dispatch_queue_t Con_Q = dispatch_queue_create("ConcurrentQ", DISPATCH_QUEUE_CONCURRENT);
    dispatch_barrier_async(Con_Q, ^{
        sleep(1);
        NSLog(@"barrier ConQ 1");
    });
    
    dispatch_barrier_async(Con_Q, ^{
        sleep(1);
        NSLog(@"barrier ConQ 2");
    });
    
    dispatch_barrier_async(Con_Q, ^{
        NSLog(@"barrier ConQ 3");
    });
    
    NSLog(@"barrier 完成");
  • 打印出来的结果,并行队列中的代码是按顺序执行的(NSlog肯定会先执行,因为是async,这里和我们说的队列中的顺序执行没有冲突)
2016-06-17 16:03:22.771 GCD_Group[28565:1718338] barrier 完成
2016-06-17 16:03:23.774 GCD_Group[28565:1718384] barrier ConQ 1
2016-06-17 16:03:24.780 GCD_Group[28565:1718384] barrier ConQ 2
2016-06-17 16:03:24.780 GCD_Group[28565:1718384] barrier ConQ 3
  • 队列必须是自行创建的串行/并行队列,才可以达到顺序执行的效果。注意,用主队列(get_main_queue)还是会阻塞主线程
    // 自定义串行队列
    dispatch_queue_t Se_Q = dispatch_queue_create("serialQ", DISPATCH_QUEUE_SERIAL);
    // 自定义并行队列
    dispatch_queue_t Con_Q = dispatch_queue_create("ConcurrentQ", DISPATCH_QUEUE_CONCURRENT);
    // 主队列
    dispatch_queue_t MainQ = dispatch_get_main_queue();
    // 全局队列
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

结论:

除了全局队列以外,剩余三种方式,都可以实现队列内的代码顺序执行。


dispatch_group 相关操作

理解

dipatch_group 相当于规定数个 blocks为group.

  • 假设一个队列中一共有5个block,我将其中的4个通过dipatch_group添加到一个队列中,那么我就可以通过下面的操作控制他们,并且知道他们完成的节点。
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // ---------------dipatch_group------------
    dispatch_group_async(gp, globalQueue, ^{
        sleep(2);
        NSLog(@"globalQueue1");
    });
    
    dispatch_group_async(gp, globalQueue, ^{
        dispatch_group_wait(gp, dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC));
        NSLog(@"globalQueue2");
    });

    dispatch_group_async(gp, globalQueue, ^{
        NSLog(@"globalQueue3");
    });
    
    dispatch_group_notify(gp, globalQueue, ^{
        NSLog(@"globalQueue 已完成");
    });
    
    dispatch_async(globalQueue, ^{
        sleep(8);
        NSLog(@"globalQueue4");
    });

日志:

2016-06-17 16:15:42.858 GCD_Group[28700:1730502] globalQueue3
2016-06-17 16:15:46.199 GCD_Group[28700:1730486] globalQueue1
2016-06-17 16:15:46.199 GCD_Group[28700:1730494] globalQueue2
2016-06-17 16:15:46.200 GCD_Group[28700:1730494] globalQueue 已完成
2016-06-17 16:15:50.863 GCD_Group[28700:1730505] globalQueue4

说明

  • 这里和采用哪个队列没有多大关系,和上面的barrier不同。
  • 阻塞一个block有两种方法:
    • sleep(n) 全局的时间休眠定时器。
  dispatch_group_wait(gp, dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC));

这个 group wait 函数只会阻塞当前 group block 里面的程序,从日志中可以看出,globalQueue3 先执行了,说明这里的等待不会阻塞所有的block.

  • group 完成时,会调用
dispatch_group_notify(group,queue,block) {}

来执行中间的内容。

dispatch_group_enter(group)、dispatch_group_leave(group)

代码

    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        sleep(5);
        NSLog(@"任务一完成");
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        sleep(8);
        NSLog(@"任务二完成");
        dispatch_group_leave(group);
    });
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"任务完成");
    });

说明

其实很好理解。 enter 和 leave 必须是成对出现的。相当于引用计数,在enter的时候+1,leave的时候-1.

  • dispatch_group_enter(group); 是告诉说下面添加的block要添加到 group中
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容