前言
當(dāng)有個需求,A,B異步請求完成之后才能請求C,D。A,B,C,D都是異步請求。這個用dispatch_group也可以實現(xiàn),只不過比dispatch_barrier麻煩一點。大家可以嘗試用dispatch_group實現(xiàn)一下,這樣能更高的理解dispatch_group。還以使用dispatch_barrier來實現(xiàn)多讀單寫的功能,下面來看看dispatch_barrier怎么來實現(xiàn)這個需求。
dispatch_barrier
dispatch_barrier 作用就是相當(dāng)于柵欄,柵欄前不管多少個異步都要執(zhí)行完畢,才會執(zhí)行柵欄后面的操作。
-
dispatch_barrier_sync
- 提交一個柵欄函數(shù)在執(zhí)行中,它會等待柵欄函數(shù)執(zhí)行完
-
dispatch_barrier_async
- 提交一個柵欄函數(shù)在異步執(zhí)行中,它會立馬返回,不需要等值返回
一、dispatch_barrier_async
下面看一下兩者共同點和區(qū)別:
//barrier 之前的并行線程執(zhí)行2s,線程執(zhí)行完畢。
//barrier 2s barrier 后面的線程并行執(zhí)行又是兩秒 總共6s.
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"休眠1s,執(zhí)行柵欄前的任務(wù)");
});
dispatch_async(queue, ^{
sleep(2);
NSLog(@"休眠2s,執(zhí)行柵欄前的任務(wù)");
});
//柵欄前所有任務(wù)執(zhí)行完畢,才開始執(zhí)行這個方法
dispatch_barrier_async(queue, ^{
sleep(2);
NSLog(@"執(zhí)行柵欄的任務(wù)");
});
NSLog(@"執(zhí)行柵欄后不在一個隊列方法");
//執(zhí)行完柵欄的方法,
dispatch_async(queue, ^{
sleep(1);
NSLog(@"休眠1s,執(zhí)行柵欄后的任務(wù)");
});
dispatch_async(queue, ^{
sleep(2);
NSLog(@"休眠2s,執(zhí)行柵欄后的任務(wù)");
});
多次執(zhí)行打印結(jié)果如下:
休眠1s,執(zhí)行柵欄前的任務(wù)
休眠2s,執(zhí)行柵欄前的任務(wù)
執(zhí)行柵欄后不在一個隊列方法
執(zhí)行柵欄的方法
休眠1s,執(zhí)行柵欄后的任務(wù)
休眠2s,執(zhí)行柵欄后的任務(wù)
執(zhí)行結(jié)果表明:
- 并行執(zhí)行柵欄前的所有任務(wù)
- dispatch_barrier_async異步方法,不阻塞當(dāng)前線程,所以先執(zhí)行柵欄后不在一個隊列方法
- 執(zhí)行柵欄里任務(wù)
- 并行執(zhí)行柵欄后的所有任務(wù)
二、dispatch_barrier_async
//barrier 之前的并行線程執(zhí)行2s,線程執(zhí)行完畢。
//barrier 2s barrier 后面的線程并行執(zhí)行又是兩秒 總共6s.
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"休眠1s,執(zhí)行柵欄前的任務(wù)");
});
dispatch_async(queue, ^{
sleep(2);
NSLog(@"休眠2s,執(zhí)行柵欄前的任務(wù)");
});
//柵欄前所有任務(wù)執(zhí)行完畢,才開始執(zhí)行這個方法
dispatch_barrier_sync(queue, ^{
sleep(2);
NSLog(@"執(zhí)行柵欄的任務(wù)");
});
NSLog(@"執(zhí)行柵欄后不在一個隊列方法");
//執(zhí)行完柵欄的方法,
dispatch_async(queue, ^{
sleep(1);
NSLog(@"休眠1s,執(zhí)行柵欄后的任務(wù)");
});
dispatch_async(queue, ^{
sleep(2);
NSLog(@"休眠2s,執(zhí)行柵欄后的任務(wù)");
});
多次執(zhí)行打印結(jié)果如下:
并行休眠1s,執(zhí)行柵欄前的任務(wù)
并行休眠2s,執(zhí)行柵欄前的任務(wù)
執(zhí)行柵欄的方法
執(zhí)行柵欄后不在一個隊列方法
并行執(zhí)行休眠1s,執(zhí)行柵欄后的任務(wù)
并行執(zhí)行休眠2s,執(zhí)行柵欄后的任務(wù)
執(zhí)行結(jié)果表明:
- 并行執(zhí)行柵欄前的所有任務(wù)
- dispatch_barrier_sync同步,阻塞當(dāng)前線程,所以先執(zhí)行柵欄里任務(wù)
- 執(zhí)行柵欄后不在一個隊列方法
- 并行執(zhí)行柵欄后的任務(wù)
實現(xiàn)多讀單寫
一、什么是多讀單寫?
可以同時有多個讀操作,而在讀操作的時候,不能有寫操作。
在寫操作的過程中,不能有其他寫操作,并且在寫操作之前,讀操作都完成。
讀操作是可以并發(fā)執(zhí)行,寫操作與(讀操作、其他寫操作)是互斥的。
二、實現(xiàn)多讀單寫的方式
- 加讀寫鎖(pthread_rwlock)來實現(xiàn)
#import <pthread.h>
@interface TKReadWhiteSafeDic() {
// 聲明一個讀寫鎖
pthread_rwlock_t lock;
// 定義一個并發(fā)隊列
dispatch_queue_t concurrent_queue;
// 用戶數(shù)據(jù)中心, 可能多個線程需要數(shù)據(jù)訪問
NSMutableDictionary *userCenterDic;
}
@end
// 多讀單寫模型
@implementation TKReadWhiteSafeDic
- (id)init {
self = [super init];
if (self) {
//初始化讀寫鎖
pthread_rwlock_init(&lock,NULL);
// 創(chuàng)建數(shù)據(jù)容器
userCenterDic = [NSMutableDictionary dictionary];
// 通過宏定義 DISPATCH_QUEUE_CONCURRENT 創(chuàng)建一個并發(fā)隊列
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來實現(xiàn)。
@interface TKReadWhiteSafeDic() {
// 定義一個并發(fā)隊列
dispatch_queue_t concurrent_queue;
// 用戶數(shù)據(jù)中心, 可能多個線程需要數(shù)據(jù)訪問
NSMutableDictionary *userCenterDic;
}
@end
// 多讀單寫模型
@implementation TKReadWhiteSafeDic
- (id)init {
self = [super init];
if (self) {
// 通過宏定義 DISPATCH_QUEUE_CONCURRENT 創(chuàng)建一個并發(fā)隊列
concurrent_queue = dispatch_queue_create("read_write_queue", DISPATCH_QUEUE_CONCURRENT);
// 創(chuàng)建數(shù)據(jù)容器
userCenterDic = [NSMutableDictionary dictionary];
}
return self;
}
- (id)objectForKey:(NSString *)key {
__block id obj;
// 同步讀取指定數(shù)據(jù)
dispatch_sync(concurrent_queue, ^{
obj = [userCenterDic objectForKey:key];
});
return obj;
}
- (void)setObject:(id)obj forKey:(NSString *)key {
// 異步柵欄調(diào)用設(shè)置數(shù)據(jù)
dispatch_barrier_async(concurrent_queue, ^{
[userCenterDic setObject:obj forKey:key];
});
}
多讀單寫的兩個困惑點解釋一下:
- 讀操作為啥同步dispatch_sync
讀的話通常都是直接想要結(jié)果,需要同步返回結(jié)果,如果是異步獲取的話就根網(wǎng)絡(luò)請求一樣了。
- 寫操作為啥異步dispatch_barrier_async
寫操作是因為不需要等待寫操作完成,所以用異步。
結(jié)尾
這個大家可以自己琢磨,做做Demo對dispatch_barrier能有更好的理解。