一、简介
IO 操作 :又叫 文件操作
文件操作分为:
- 从文件中读取内容,例如:视频文件,mp3 文件,文本文件。
- 往文件中写入内容。
危险的文件操作是:
- 线程A 从文件中读取内容的同时,线程B 往文件中写入内容。也就是同一时间段即读取文件,又写入文件。
- 这样的操作是 要杜绝的。
二、模拟读取与写入操作
模拟 :两条线程,一条读取,一条写入。可能两个线程同时操作。
解决方案一:信号量 dispatch_semaphore_t
* 这种方案在文件读取写入时不是最理想的方案。
* 因为当我们为了提高性能效率要保证读
这个操作可以同时进行。而信号量只能 同一时刻做一件事情(因为信号量写的是 1)。
* 因为读取的数据都是一样的。但写入的数据就不是一样的了。读取数据不会破坏以前的数据
* 多读单写
* 多线程牵扯到 安全问题,就是因为有一条线程进行了写入操作。如果都是读取操作根本就不会造成线程安全问题。
*
@property(strong,nonatomic) dispatch_semaphore_t semaphore;
解决方案二:读取不加锁,写入加锁
- 这种方案也不可取,因为 有可能同时读取和写入,这样会造成数据的不准确
总结: 读写安全方案希望实现以下场景
- 同一时间,只能有1个线程进行写入操作
- 同一时间,允许有多个线程进行读取操作
- 同一时间,不允许既有写入操作,又有读取操作。
这个总结:就是单行的 “多读单写”,经常用于文件等数据的读写操作。
三、多读单写
iOS 中的实现方案:
- pthread_rwlock:读写锁
- dispatch_barrier_async:异步栅栏调用
四、pthread_rwlock 读写锁
@interface ViewController ()
@property (assign, nonatomic) pthread_rwlock_t lock;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化锁
pthread_rwlock_init(&_lock, NULL);
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
[self read];
});
dispatch_async(queue, ^{
[self write];
});
}
}
- (void)read {
pthread_rwlock_rdlock(&_lock);
sleep(1);
NSLog(@"%s", __func__);
pthread_rwlock_unlock(&_lock);
}
- (void)write {
pthread_rwlock_wrlock(&_lock);
sleep(1);
NSLog(@"%s", __func__);
pthread_rwlock_unlock(&_lock);
}
- (void)dealloc {
pthread_rwlock_destroy(&_lock);
}
五、dispatch_barrier_async 异步栅栏调用
- 这个函数传入的并发队列必须是自己通过dispatch_queue_cretate创建的
- 如果传入的是一个串行或是一个全局的并发队列,那这个函数便等同于dispatch_async函数的效果