dispatch_barrier
讲完了GCD详解一。我们来看看一个不太常用的GCD。dispatch_barrier。 这个barrier我感觉使用霸道总裁形容比较合适。这里借用raywenderlich上介绍barrier的一张图。
看的有点懵逼?
不要紧。我来解释一下。 首先,在一个并行队列中,有多个线程在执行多个任务,在这个并行队列中,有一个dispatch_barrier任务。这样会有一个什么效果呢? 就是,所有在这个dispatch_barrier之后的任务总会等待barrier之前的所有任务结束之后,才会执行。那么细心的同学可能会发现这里有个问题,既然所有在barrier之后的任务都会等待在barrier之前的任务结束之后执行,那么barrier本身执行是否会阻塞当前线程? 所以,dispatch_barrier也是有两个方法的。dispatch_barrier_sync和dispatch_barrier_async.
dispatch_barrier_sync
还是看代码理解的更快一点。代码如下:
-(void)testBarrierSyncWithConcurrentQueue
{
dispatch_queue_t concurrtqueue = dispatch_queue_create("thread", DISPATCH_QUEUE_CONCURRENT);
for (int index=0; index<10; index++) {
dispatch_async(concurrtqueue, ^{
NSLog(@"index = --%d",index);
});
}
for (int j=0; j<50000; j++) {
dispatch_barrier_sync(concurrtqueue, ^{
if (j == 50000-1) {
NSLog(@"barrier finished");
NSLog(@"currt thread is %@",[NSThread currentThread]);
}
});
}
NSLog(@"Running on thread");
for (int index = 10; index<20; index++) {
dispatch_async(concurrtqueue, ^{
NSLog(@"index = %d",index);
});
}
}
运行之后的输出结果是:
2018-01-31 16:56:17.519821+0800 TextD[24970:708808] index = --0
2018-01-31 16:56:17.519821+0800 TextD[24970:708810] index = --1 2018-01-31 16:56:17.519822+0800 TextD[24970:708809] index = --2
2018-01-31 16:56:17.519835+0800 TextD[24970:708807] index = --3
2018-01-31 16:56:17.520029+0800 TextD[24970:708808] index = --4
2018-01-31 16:56:17.520037+0800 TextD[24970:708809] index = --5
2018-01-31 16:56:17.520040+0800 TextD[24970:708807] index = --6
2018-01-31 16:56:17.520047+0800 TextD[24970:708810] index = --7
2018-01-31 16:56:17.520113+0800 TextD[24970:708911] index = --8
2018-01-31 16:56:17.520125+0800 TextD[24970:708910] index = --9
2018-01-31 16:56:17.525035+0800 TextD[24970:708717] barrier finished
2018-01-31 16:56:17.525376+0800 TextD[24970:708717] currt thread is<NSThread: 0x604000070f00>{number = 1, name = main}
2018-01-31 16:56:17.525520+0800 TextD[24970:708717] Running on thread
2018-01-31 16:56:17.525684+0800 TextD[24970:708910] index = 10
2018-01-31 16:56:17.525694+0800 TextD[24970:708911] index = 11
2018-01-31 16:56:17.525712+0800 TextD[24970:708810] index = 12
2018-01-31 16:56:17.525732+0800 TextD[24970:708807] index = 13
2018-01-31 16:56:17.525740+0800 TextD[24970:708809] index = 14
2018-01-31 16:56:17.525769+0800 TextD[24970:708808] index = 15
2018-01-31 16:56:17.525825+0800 TextD[24970:708912] index = 16
2018-01-31 16:56:17.525870+0800 TextD[24970:708910] index = 18
2018-01-31 16:56:17.525878+0800 TextD[24970:708913] index = 17
2018-01-31 16:56:17.525914+0800 TextD[24970:708914] index = 19
ok,总结一下。
dispatch_barrier_sync确实是会在队列中充当一个栅栏的作用,凡是在他之后进入队列的任务,总会在dispatch_barrier_sync之前的所有任务执行完毕之后才执行。
见名知意,dispatch_barrier_sync是会在主线程执行队列中的任务的,所以,Running on Main Thread这句话会被阻塞,从而在barrier之后执行。
dispatch_barrier_async
再看看dispatch_barrier_async执行的效果。
代码如下:
-(void)testBarrierAsyncWithConcurrentQueue
{
dispatch_queue_t concurrtqueue = dispatch_queue_create("thread", DISPATCH_QUEUE_CONCURRENT);
for (int index=0; index<10; index++) {
dispatch_async(concurrtqueue, ^{
NSLog(@"index = --%d",index);
});
}
for (int j=0; j<1000000; j++) {
dispatch_barrier_async(concurrtqueue, ^{
if (j == 1000000-1) {
NSLog(@"barrier finished");
NSLog(@"currt thread is %@",[NSThread currentThread]);
}
});
}
NSLog(@"Running on thread");
for (int index = 10; index<20; index++) {
dispatch_async(concurrtqueue, ^{
NSLog(@"index = %d",index);
});
}
}
结果如下:
2018-02-01 15:21:45.486359+0800 TextD[3219:197349] index = --2
2018-02-01 15:21:45.486359+0800 TextD[3219:197351] index = --1
2018-02-01 15:21:45.486359+0800 TextD[3219:197352] index = --02018-02-01 15:21:45.486386+0800 TextD[3219:197348] index = --3
2018-02-01 15:21:45.486650+0800 TextD[3219:197351] index = --5
2018-02-01 15:21:45.486649+0800 TextD[3219:197352] index = --4
2018-02-01 15:21:45.486687+0800 TextD[3219:197350] index = --6
2018-02-01 15:21:45.486688+0800 TextD[3219:197349] index = --7
2018-02-01 15:21:45.486736+0800 TextD[3219:197359] index = --8
2018-02-01 15:21:45.486753+0800 TextD[3219:197360] index = --9
2018-02-01 15:21:48.984586+0800 TextD[3219:197244] Running on thread
2018-02-01 15:21:48.997644+0800 TextD[3219:197360] barrier finished
2018-02-01 15:21:48.997871+0800 TextD[3219:197360] currt thread is<NSThread: 0x6040004706c0>{number = 3, name = (null)}
2018-02-01 15:21:48.998662+0800 TextD[3219:197360] index = 11
2018-02-01 15:21:48.998662+0800 TextD[3219:197350] index = 10
2018-02-01 15:21:48.998693+0800 TextD[3219:197349] index = 12
2018-02-01 15:21:48.998714+0800 TextD[3219:197352] index = 13
2018-02-01 15:21:48.998733+0800 TextD[3219:197351] index = 14
2018-02-01 15:21:48.998750+0800 TextD[3219:197348] index = 15
2018-02-01 15:21:48.998786+0800 TextD[3219:197359] index = 16
2018-02-01 15:21:48.998866+0800 TextD[3219:197401] index = 17
2018-02-01 15:21:48.998891+0800 TextD[3219:197402] index = 18
2018-02-01 15:21:48.998916+0800 TextD[3219:197403] index = 19
dispatch_barrier_async会开辟一条新的线程执行其中的任务,所以不会阻塞当前线程。其他的功能和dispatch_barrier_sync相同。
几个小问题
1.为什么我们只举了barrier和并行队列的例子,而没有举barrier和串行队列的例子?
因为,barrier和串行队列配合是完全没有意义的。barrier的目的是什么?目的是为了在某种情况下,同一个队列中一些并发任务必须在另一些并发任务之后执行,所以需要一个类似于拦截的功能,迫使后执”
“行的任务必须等待。那么,串行队列中的所有任务本身就是按照顺序执行的,那么又有什么必要使用拦截的功能呢?
2.在global queue中使用barrier没有意义,为什么?
barrier实现的基本条件是,要写在同一队列中。举个例子,你现在创建了两个并行队列,你在其中一个队列中插入了一个barrier任务,那么你不可能期待他可以在第二个队列中生效,对吧。同样的,每一次使用global queue,系统分配给你的可能是不同的并行队列,你在其中插入一个barrier任务,又有什么意义呢?
网友评论