关于GCD的理解,可以参看本博另一篇文章
dispatch_barrier_async 实现顺序执行。
根据上一篇文章的理解,如果调用 dipatch_async,异步添加到并行队列中,应该是无法控制执行顺序的。
但是通过dipatch_barrier_async可以实现顺序操作。
dispatch_barrier 说明
使用dispatch_barrier将任务加入到并行队列之后,任务会在前面任务全部执行完成之后执行,任务执行过程中,其他任务无法执行,直到barrier任务执行完成
代码
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中