理解多读单写和栅栏函数

1,583 阅读1分钟

先来看栅栏函数 dispatch_barrier_sync 和dispatch_barrier_async 1.dispatch_barrier:是一个拦截函数. 2.dispatch_barrier:要想拦截成功必须站在一条路上,也就是位于同一线程.

下面来看第一个:dispatch_barrier_sync 代码:

    dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue2 = dispatch_queue_create("myQueue2", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
           //任务1
           for (int i = 0; i < 5; i++) {
               NSLog(@"任务一、来自线程:%@",[NSThread currentThread]);
           }
       });
    
    dispatch_async(queue, ^{
           //任务1
           for (int i = 0; i < 5; i++) {
               NSLog(@"任务二、来自线程:%@",[NSThread currentThread]);
           }
       });
    dispatch_barrier_sync(queue, ^{
        //栅栏
           for (int i = 0; i < 1 ; i++) {
               NSLog(@"任务拦截、来自线程:%@",[NSThread currentThread]);
           }
    });
    NSLog(@"任务xxxxxx路人甲");
    dispatch_async(queue, ^{
           //任务1
           for (int i = 0; i < 2; i++) {
               NSLog(@"任务三、来自线程:%@",[NSThread currentThread]);
           }
       });

输出入结果

16294508669097.jpg 这里注意:路人甲的 和任务三的执行顺序.

再来看一下dispatch_barrier_async输出:

16294510130976.jpg 区别:

路人甲 在dispatch_barrier_sync下是要等栅栏函数执行完成才执行 而在dispatch_barrier_async下是先执行的 任务三 无论都在栅栏函数之后执行的

这以上就是栅栏函数的同步和异步的区别.

理解了上面我们再来看使用dispatch_barrier来实现多读单写: 多读单写的定义:

  1. 读并发执行,写同步执行
  2. 读和写是互斥的,读是需要等待结果返回的
  3. 写之前要等所有读操作完成之后开始,写不用等结果

上面的条件要求中: 1."写之前要等所有读操作完成之后开始":这个就是栅栏函数,"不用等结果":async 2."读并发执行":就是并发队列,"读要等结果":就是同步sync 3.栅栏函数起作用的条件就是在同一线程

所以多读单写的实现如下:

#import "SXReadWriteSafeDic.h"
@interface SXReadWriteSafeDic ()
{
  // 定义一个并发队列
  dispatch_queue_t concurrent_queue;
  
  // 用户数据中心, 可能多个线程需要数据访问
  NSMutableDictionary *userCenterDic;
}
@end
@implementation SXReadWriteSafeDic

- (instancetype)init
{
  self = [super init];
  if (self) {
      concurrent_queue = dispatch_queue_create("readWriteSafeQ", DISPATCH_QUEUE_CONCURRENT);
      userCenterDic = [NSMutableDictionary dictionary];
  }
  return self;
}
///:读要求:
///1. 读操作要等结果:sync
///2.要和写操作互斥:在同一线程
///3.多读:concurrent_queue 并发线程
- (id)objecForKey:(NSString *)key {
  __block id obj;
  dispatch_sync(concurrent_queue, ^{
      obj  = userCenterDic[key];
  });
  return obj;
}
///写要求:
/// 1.和读互斥:栅栏函数
///2.等所有读操作完成之后
///3.写操作不用等待结果:async
- (void)setObejct:(id)obj forKey:(NSString *)key {
  dispatch_barrier_async(concurrent_queue, ^{
      [self->userCenterDic setObject:obj forKey:key];
  });
}

加深理解,如有问题欢迎指正.