iOS 多線程之dispatch_barrier及實現(xiàn)多讀單寫

前言

當有個需求鹊碍,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 作用就是相當于柵欄罐柳,柵欄前不管多少個異步都要執(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í)行柵欄前的任務");
    });
    
    dispatch_async(queue, ^{
       
        sleep(2);
        NSLog(@"休眠2s,執(zhí)行柵欄前的任務");
    });
    
    //柵欄前所有任務執(zhí)行完畢创南,才開始執(zhí)行這個方法
    dispatch_barrier_async(queue, ^{
    
        sleep(2);
        NSLog(@"執(zhí)行柵欄的任務");
    });
    NSLog(@"執(zhí)行柵欄后不在一個隊列方法");
    //執(zhí)行完柵欄的方法伦忠,
    dispatch_async(queue, ^{
        
        sleep(1);
        NSLog(@"休眠1s,執(zhí)行柵欄后的任務");
    });
  
    dispatch_async(queue, ^{
    
        sleep(2);
        NSLog(@"休眠2s扰藕,執(zhí)行柵欄后的任務");
    });

多次執(zhí)行打印結果如下:

休眠1s缓苛,執(zhí)行柵欄前的任務
休眠2s,執(zhí)行柵欄前的任務
執(zhí)行柵欄后不在一個隊列方法
執(zhí)行柵欄的方法
休眠1s邓深,執(zhí)行柵欄后的任務
休眠2s未桥,執(zhí)行柵欄后的任務

執(zhí)行結果表明:

  • 并行執(zhí)行柵欄前的所有任務
  • dispatch_barrier_async異步方法,不阻塞當前線程芥备,所以先執(zhí)行柵欄后不在一個隊列方法
  • 執(zhí)行柵欄里任務
  • 并行執(zhí)行柵欄后的所有任務

二冬耿、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í)行柵欄前的任務");
    });
    
    dispatch_async(queue, ^{
       
        sleep(2);
        NSLog(@"休眠2s,執(zhí)行柵欄前的任務");
    });
    
    //柵欄前所有任務執(zhí)行完畢袱瓮,才開始執(zhí)行這個方法
    dispatch_barrier_sync(queue, ^{
    
        sleep(2);
        NSLog(@"執(zhí)行柵欄的任務");
    });
    NSLog(@"執(zhí)行柵欄后不在一個隊列方法");
    //執(zhí)行完柵欄的方法缤骨,
    dispatch_async(queue, ^{
        
        sleep(1);
        NSLog(@"休眠1s,執(zhí)行柵欄后的任務");
    });
  
    dispatch_async(queue, ^{
    
        sleep(2);
        NSLog(@"休眠2s尺借,執(zhí)行柵欄后的任務");
    });

多次執(zhí)行打印結果如下:

并行休眠1s绊起,執(zhí)行柵欄前的任務
并行休眠2s,執(zhí)行柵欄前的任務
執(zhí)行柵欄的方法
執(zhí)行柵欄后不在一個隊列方法
并行執(zhí)行休眠1s燎斩,執(zhí)行柵欄后的任務
并行執(zhí)行休眠2s虱歪,執(zhí)行柵欄后的任務

執(zhí)行結果表明:

  • 并行執(zhí)行柵欄前的所有任務
  • dispatch_barrier_sync同步,阻塞當前線程栅表,所以先執(zhí)行柵欄里任務
  • 執(zhí)行柵欄后不在一個隊列方法
  • 并行執(zhí)行柵欄后的任務

實現(xiàn)多讀單寫

一笋鄙、什么是多讀單寫?

  • 可以同時有多個讀操作怪瓶,而在讀操作的時候萧落,不能有寫操作。

  • 在寫操作的過程中洗贰,不能有其他寫操作找岖,并且在寫操作之前,讀操作都完成哆姻。

  • 讀操作是可以并發(fā)執(zhí)行宣增,寫操作與(讀操作、其他寫操作)是互斥的矛缨。

二爹脾、實現(xiàn)多讀單寫的方式

  1. 加讀寫鎖(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);    
}

  1. 使用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ù)據(jù)
    dispatch_barrier_async(concurrent_queue, ^{
        [userCenterDic setObject:obj forKey:key];
    });
}

多讀單寫的兩個困惑點解釋一下:

  • 讀操作為啥同步dispatch_sync

讀的話通常都是直接想要結果箕昭,需要同步返回結果灵妨,如果是異步獲取的話就根網(wǎng)絡請求一樣了。

  • 寫操作為啥異步dispatch_barrier_async

寫操作是因為不需要等待寫操作完成落竹,所以用異步泌霍。

結尾

這個大家可以自己琢磨,做做Demo對dispatch_barrier能有更好的理解述召。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末朱转,一起剝皮案震驚了整個濱河市蟹地,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌藤为,老刑警劉巖怪与,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缅疟,居然都是意外死亡分别,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門存淫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耘斩,“玉大人,你說我怎么就攤上這事桅咆±ㄊ冢” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵轧邪,是天一觀的道長刽脖。 經(jīng)常有香客問我,道長忌愚,這世上最難降的妖魔是什么曲管? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮硕糊,結果婚禮上院水,老公的妹妹穿的比我還像新娘。我一直安慰自己简十,他們只是感情好檬某,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著螟蝙,像睡著了一般恢恼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上胰默,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天场斑,我揣著相機與錄音,去河邊找鬼牵署。 笑死漏隐,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的奴迅。 我是一名探鬼主播青责,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了脖隶?” 一聲冷哼從身側響起扁耐,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎浩村,沒想到半個月后做葵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體占哟,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡心墅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了榨乎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怎燥。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蜜暑,靈堂內(nèi)的尸體忽然破棺而出铐姚,到底是詐尸還是另有隱情,我是刑警寧澤肛捍,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布隐绵,位于F島的核電站,受9級特大地震影響拙毫,放射性物質(zhì)發(fā)生泄漏依许。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一缀蹄、第九天 我趴在偏房一處隱蔽的房頂上張望峭跳。 院中可真熱鬧,春花似錦缺前、人聲如沸蛀醉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拯刁。三九已至,卻和暖如春逝段,著一層夾襖步出監(jiān)牢的瞬間垛玻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工惹恃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夭谤,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓巫糙,卻偏偏與公主長得像朗儒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容