iOS|iOS 底层 - 多线程读写安全

本文源自本人的学习记录整理与理解,其中参考阅读了部分优秀的博客和书籍,尽量以通俗简单的语句转述。引用到的地方如有遗漏或未能一一列举原文出处还望见谅与指出,另文章内容如有不妥之处还望指教,万分感谢 !
思考如何实现以下场景
1. 同一时间,只能有1个线程进行写的操作
2. 同一时间,允许有多个线程进行读的操作
3. 同一时间,不允许既有写的操作,又有读的操作
上面的场景就是典型的“多读单写”,经常用于文件等数据的读写操作,iOS中的实现方案有

  • pthread_rwlock:读写锁
  • dispatch_barrier_async:异步栅栏([zhà lan])调用
    • dispatch_barrier_async 函数的作用与barrier的意思相同,在进程管理中起到一个栅栏的作用,它等待所有位于barrier函数之前的操作执行完毕后执行,并且在barrier函数执行之后,barrier函数之后的操作才会得到执行
    • 这个函数传入的并发队列必须是自己通过dispatch_queue_cretate创建的
    • 如果传入的是一个串行或是一个全局的并发队列,那这个函数便等同于dispatch_async函数的效果,就失去了barrier的意义
这样的实现方案类似于后端实现I/O的经典方案ReactorProactor
  • Reactor模式用于同步I/O操作,Proactor模式用于异步I/O操作
Reactor
pthread_rwlock 使用
//1. 声明 @property (assign, nonatomic) pthread_rwlock_t lock; // 2. 初始化锁 pthread_rwlock_init(&_lock, NULL); //3. 读操作 - (void)read { pthread_rwlock_rdlock(&_lock); sleep(1); NSLog(@"%s", __func__); pthread_rwlock_unlock(&_lock); } //4. 写操作 - (void)write { pthread_rwlock_wrlock(&_lock); sleep(1); NSLog(@"%s", __func__); pthread_rwlock_unlock(&_lock); } //5. 释放 - (void)dealloc { pthread_rwlock_destroy(&_lock); }

dispatch_barrier_async 使用
//1.声明队列 @property (strong, nonatomic) dispatch_queue_t queue; //2. 创建队列 self.queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT); //多线程并发读写 for (int i = 0; i < 10; i++) { dispatch_async(self.queue, ^{ [self read]; }); dispatch_async(self.queue, ^{ [self read]; }); dispatch_async(self.queue, ^{ [self read]; }); //3. 写入操作 dispatch_barrier_async(self.queue, ^{ [self write]; }); } - (void)read { sleep(1); NSLog(@"read"); }- (void)write { sleep(1); NSLog(@"write"); }

输出结果:
【iOS|iOS 底层 - 多线程读写安全】2020-04-13 15:30:34.788209+0800-读写安全 read
2020-04-13 15:30:34.788209+0800-读写安全 read
2020-04-13 15:30:34.788283+0800-读写安全 read
2020-04-13 15:30:35.789804+0800-读写安全 write

    推荐阅读