比如在内存中维护一份数据,有多处地方可能会同时操作这块数据,怎么能保证数据安全?这道题目总结得到要满足以下三点:
- 1.读写互斥
- 2.写写互斥
- 3.读读并发
@implementation KCPerson
- (instancetype)init
{
if (self = [super init]) {
_concurrentQueue = dispatch_queue_create("com.kc_person.syncQueue", DISPATCH_QUEUE_CONCURRENT);
_dic = [NSMutableDictionary dictionary];
}
return self;
}
- (void)kc_setSafeObject:(id)object forKey:(NSString *)key{
key = [key copy];
dispatch_barrier_async(_concurrentQueue, ^{
[_dic setObject:object key:key];
});
}
- (id)kc_safeObjectForKey::(NSString *)key{
__block NSString *temp;
dispatch_sync(_concurrentQueue, ^{
temp =[_dic objectForKey:key];
});
return temp;
}
@end
首先我们要维系一个GCD 队列,最好不用全局队列,毕竟大家都知道全局队列遇到栅栏函数是有坑点的,这里就不分析了!
因为考虑性能 死锁 堵塞的因素不考虑串行队列,用的是自定义的并发队列!
_concurrentQueue = dispatch_queue_create("com.kc_person.syncQueue", DISPATCH_QUEUE_CONCURRENT);
-
首先我们来看看读操作:kc_safeObjectForKey我们考虑到多线程影响是不能用异步函数的!说明:
- 线程2 获取:
name
线程3 获取age
- 如果因为异步并发,导致混乱 本来读的是
name
结果读到了age
- 我们允许多个任务同时进去! 但是读操作需要同步返回,所以我们选择:同步函数(读读并发)
- 线程2 获取:
我们再来看看写操作,在写操作的时候对key进行了copy, 关于此处的解释,插入一段来自参考文献的引用:
函数调用者可以自由传递一个
NSMutableString
的key
,并且能够在函数返回后修改它。因此我们必须对传入的字符串使用copy
操作以确保函数能够正确地工作。如果传入的字符串不是可变的(也就是正常的NSString
类型),调用copy
基本上是个空操作。
- 这里我们选择dispatch_barrier_async, 为什么是栅栏函数而不是异步函数或者同步函数,下面分析:
- 栅栏函数任务:之前所有的任务执行完毕,并且在它后面的任务开始之前,期间不会有其他的任务执行,这样比较好的促使 写操作一个接一个写 (写写互斥),不会乱!
- 为什么不是异步函数?应该很容易分析,毕竟会产生混乱!
- 为什么不用同步函数?如果读写都操作了,那么用同步函数,就有可能存在:我写需要等待读操作回来才能执行,显然这里是不合理!