什么是多读单写?
多个线程同时读一个变量是不需要同步的,而多个线程同时写一个变量或一个线程写而其他线程读某个变量,是需要同步的,可以总结为:“多读不互斥,而读写和多写互斥”。
实现方案:
一、加读写锁 pthread_rwlock
来实现
#import <pthread.h>
@interface FTReadWhiteSafeDic() {
// 声明一个读写锁
pthread_rwlock_t lock;
// 定义一个并发队列
dispatch_queue_t concurrent_queue;
// 用户数据中心, 可能多个线程需要数据访问
NSMutableDictionary *userCenterDic;
}
@end
// 多读单写模型
@implementation FTReadWhiteSafeDic
- (id)init {
self = [super init];
if (self) {
//初始化读写锁
pthread_rwlock_init(&lock,NULL);
// 创建数据容器
userCenterDic = [NSMutableDictionary dictionary];
// 通过宏定义 DISPATCH_QUEUE_CONCURRENT 创建一个并发队列
concurrent_queue = dispatch_queue_create("read_write_queue", DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
- (id)objectForKey:(NSString *)key {
//加读锁
pthread_rwlock_rdlock(&_rwlock);
id obj = [userCenterDic objectForKey:key];
pthread_rwlock_unlock(&_rwlock);
return obj;
}
- (void)setObject:(id)obj forKey:(NSString *)key {
//加写锁
pthread_rwlock_wrlock(&_rwlock);
[userCenterDic setObject:obj forKey:key];
pthread_rwlock_unlock(&_rwlock);
}
二、使用 dispatch_barrie
来实现。
@interface FTReadWhiteSafeDic() {
// 定义一个并发队列
dispatch_queue_t concurrent_queue;
// 用户数据中心, 可能多个线程需要数据访问
NSMutableDictionary *userCenterDic;
}
@end
// 多读单写模型
@implementation FTReadWhiteSafeDic
- (id)init {
self = [super init];
if (self) {
// 通过宏定义 DISPATCH_QUEUE_CONCURRENT 创建一个并发队列
concurrent_queue = dispatch_queue_create("read_write_queue", DISPATCH_QUEUE_CONCURRENT);
// 创建数据容器
userCenterDic = [NSMutableDictionary dictionary];
}
return self;
}
- (id)objectForKey:(NSString *)key {
__block id obj;
// 异步读取指定数据
dispatch_async(concurrent_queue, ^{// dispatch_sync 设置为同步读取
obj = [userCenterDic objectForKey:key];
});
return obj;
}
- (void)setObject:(id)obj forKey:(NSString *)key {
// 异步栅栏调用设置数据
dispatch_barrier_async(concurrent_queue, ^{
[userCenterDic setObject:obj forKey:key];
});
}
注意点:
- 读操作
dispatch_async
与dispatch_sync
区别
dispatch_async
并发异步回调方式读取数据,当你对外部调用顺序没有要求时,可以这么调用。
dispatch_sync
并发同步读取数据,能保证外部调用顺序。此时会堵塞当前线程,当前线程需要等待读取任务执行完成,才能继续执行后边代码任务。
(id)objectForKey:(NSString *)key {
obj = [userCenterDic objectForKey:key];__block id obj;
// 异步读取指定数据
dispatch_async(concurrent_queue, ^{// dispatch_sync 设置为同步读取
});
return obj;
}
这里 async 会 返回 nil
兄弟写的非常好 https://www.cscnn.com/
博主太厉害了!