3.2.7 dispatch_barrier_async
在访问数据库或文件时,如前所述,使用Serial Dispatch Queue 可避免数据竞争的问题。
写入处理确实不可与其他的写入处理以及包含读取处理的其他某些处理并行执行。但是如果读取处理只是与读取处理并行执行,那么多个并行执行就不会发生问题。
也就是说,为了高效率地进行访问,读取处理追加到Concurrent Dispatch Queue中,写入处理在任一个读取处理没有执行的状态下,追加到Serial Dispatch Queue 中即可(在写入处理结束之前,读取处理不可执行)。
虽然利用Dispatch Group 和 dispatch_set_target_queue函数也可实现,但是源代码会很复杂。
GCD为我们提供了更为聪明的解决方法——dispatch_barrier_async 函数。该函数同 dispatch_queue_create函数生成 Concurrent Dispatch Queue 一起使用。
- 首先dispatch_queue_create函数生成Concurrent Dispatch Queue,在dispatch_async 函数中追加读取处理
-(void)barrier {
/**
dispatch_barrier_sync和dispatch_barrier_async的共同点:
1、都会等待在它前面插入队列的任务(0、1、2,3)先执行完
2、都会等待他们自己的任务执行完再执行后面的任务(4、5、6、7)
dispatch_barrier_sync和dispatch_barrier_async的不共同点:
在将任务插入到queue的时候,dispatch_barrier_sync需要等待自己的任务结束之后才会继续程序,然后插入被写在它后面的任务(4、5、6),然后执行后面的任务
而dispatch_barrier_async将自己的任务插入到queue之后,不会等待自己的任务结束,它会继续把后面的任务(4、5、6)插入到queue
*/
dispatch_queue_t queue = dispatch_queue_create("com.example.gcd.forBarrier", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"blk0_for_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk1_for_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk2_for_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk3_for_reading");
});
/**
写入处理
dispatch_barrier_async 函数的作用是在等待追加的处理全部执行结束后,再追加处理到Dispatch Queue 中
*/
dispatch_barrier_async(queue, ^{
NSLog(@"blk_for_writing");
});
/**
写入处理
dispatch_barrier_async函数的作用是等待追加的处理执行结束
*/
// dispatch_barrier_sync(queue, ^{
// NSLog(@"blk_for_writing");
// });
NSLog(@"aaa");
dispatch_async(queue, ^{
NSLog(@"blk4_for_reading");
});
NSLog(@"bbb");
dispatch_async(queue, ^{
NSLog(@"blk5_for_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk6_for_reading");
});
dispatch_async(queue, ^{
NSLog(@"blk7_for_reading");
});
}
- 在 blk3_for_reading 处理和 blk4_for_reading 处理之间执行写入处理,并将写入的内容 在blk4_for_reading处理以及之后的处理中进行读取。
使用Concurrent Dispatch Queue 和dispatch_barrier_async 函数可实现高效率的数据库访问和文件访问。