比如在內(nèi)存中維護(hù)一份數(shù)據(jù),有多處地方可能會同時操作這塊數(shù)據(jù),怎么能保證數(shù)據(jù)安全?這道題目總結(jié)得到要滿足以下三點:
- 1.讀寫互斥
- 2.寫寫互斥
- 3.讀讀并發(fā)
@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 隊列,最好不用全局隊列,畢竟大家都知道全局隊列遇到柵欄函數(shù)是有坑點的,這里就不分析了!
因為考慮性能 死鎖 堵塞的因素不考慮串行隊列,用的是自定義的并發(fā)隊列!
_concurrentQueue = dispatch_queue_create("com.kc_person.syncQueue", DISPATCH_QUEUE_CONCURRENT);-
首先我們來看看讀操作:kc_safeObjectForKey我們考慮到多線程影響是不能用異步函數(shù)的!說明:
- 線程2 獲取:
name線程3 獲取age - 如果因為異步并發(fā),導(dǎo)致混亂 本來讀的是
name結(jié)果讀到了age - 我們允許多個任務(wù)同時進(jìn)去! 但是讀操作需要同步返回,所以我們選擇:同步函數(shù)(讀讀并發(fā))
- 線程2 獲取:
我們再來看看寫操作,在寫操作的時候?qū)ey進(jìn)行了copy, 關(guān)于此處的解釋,插入一段來自參考文獻(xiàn)的引用:
函數(shù)調(diào)用者可以自由傳遞一個
NSMutableString的key,并且能夠在函數(shù)返回后修改它。因此我們必須對傳入的字符串使用copy操作以確保函數(shù)能夠正確地工作。如果傳入的字符串不是可變的(也就是正常的NSString類型),調(diào)用copy基本上是個空操作。
- 這里我們選擇dispatch_barrier_async, 為什么是柵欄函數(shù)而不是異步函數(shù)或者同步函數(shù),下面分析:
- 柵欄函數(shù)任務(wù):之前所有的任務(wù)執(zhí)行完畢,并且在它后面的任務(wù)開始之前,期間不會有其他的任務(wù)執(zhí)行,這樣比較好的促使 寫操作一個接一個寫 (寫寫互斥),不會亂!
- 為什么不是異步函數(shù)?應(yīng)該很容易分析,畢竟會產(chǎn)生混亂!
- 為什么不用同步函數(shù)?如果讀寫都操作了,那么用同步函數(shù),就有可能存在:我寫需要等待讀操作回來才能執(zhí)行,顯然這里是不合理!