iOS開發(fā) 之 barrier GCD

本文Demo的完整工程代碼, 參考這里的GCDDemo

目錄

引言

GCD是iOS開發(fā)中一個"老生常談"的話題了, 例如之前的幾篇文章

但是最近在閱讀SDWebImage源碼時(詳見iOS開發(fā) 之 SDWebImage源碼分析), 還是遇到了不知道的GCD

它就是本文的主角: barrier GCD, 即dispatch_barrier_sync和dispatch_barrier_async這兩個接口

折騰了好久, 總算弄明白sync與async, serial queue與concurrent queue, 怎么又來了個barrier, 到底什么玩意?

不急, 下面我們就來一探究竟

回顧

在討論barrier之前, 我們有必要再對GCD做一個簡單的回顧

  • GCD的queue分為serial queue和concurrent queue兩種, 其中系統(tǒng)為我們創(chuàng)建的serial queue通過dispatch_get_main_queue來獲取, concurrent queue通過dispatch_get_global_queue來獲取

  • GCD的queue與thread并無直接映射關(guān)系, async的block可能在子線程也有可能在ui thread中執(zhí)行(詳見iOS開發(fā) 之 Queue和Thread), 這也是GCD的價值所在, 讓開發(fā)者關(guān)注隊列而非線程

  • GCD的async接口, 將block添加到queue后會立即返回, 而sync接口與async正好相反, 將block添加到queue后直到block執(zhí)行結(jié)束后才返回

  • 在當(dāng)前線程中調(diào)用sync接口, 會引起死鎖(詳見iOS開發(fā) 之 Queue和Thread)

barrier GCD

首先我們來看下什么是barrier GCD, Apple Documentation對dispatch_barrier_async的解釋如下

Calls to this function always return immediately after the block has been submitted and never wait for the block to be invoked. When the barrier block reaches the front of a private concurrent queue, it is not executed immediately. Instead, the queue waits until its currently executing blocks finish executing. At that point, the barrier block executes by itself. Any blocks submitted after the barrier block are not executed until the barrier block completes.

The queue you specify should be a concurrent queue that you create yourself using the dispatch_queue_create function. If the queue you pass to this function is a serial queue or one of the global concurrent queues, this function behaves like the dispatch_async function.

dispatch_barrier_sync和dispatch_barrier_async其實是類似的(除了sync與async的區(qū)別), 所以本文重點討論其中的一個接口

很多文章對官方解釋做了詳盡的翻譯(例如可以參考Dispatch_barrier_async的研究), 而我更習(xí)慣于提煉其中的幾個要點如下

  • 通過dispatch_barrier_async添加的block會等到之前添加所有的block執(zhí)行完畢再執(zhí)行

  • 在dispatch_barrier_async之后添加的block會等到dispatch_barrier_async添加的block執(zhí)行完畢再執(zhí)行

  • dispatch_barrier_async的上述特點只在自己創(chuàng)建的concurrent queue有效, 在serial queue和global concurrent queues中的作用和dispatch_sync完全相同

雖說是要點, 但是怎么感覺還是有點繞啊, 沒關(guān)系, 重點來了

請問barrier的含義是? 沒錯, 這個確實是重點

barrier: 障礙物, 屏障, 界線

知道了barrier的含義, 理解dispatch_barrier_async就變得很輕松了:

以barrier為分界, 前面的執(zhí)行完才能執(zhí)行后面的

例子

概念介紹完了, 如果你還沒理解的話, 也沒關(guān)系, 我們來看下面的例子

- (IBAction)buttonOnClicked:(UIButton *)sender {
    dispatch_queue_t queue = dispatch_queue_create("My concurrent queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_suspend(queue);
    
    // Enqueue five blocks
    for (int index = 0; index < 5; ++index) {
        dispatch_async(queue, ^{
            [self printNumber:index];
        });
    }
    
    // Enqueue a barrier
    dispatch_barrier_async(queue, ^{
        NSLog(@"--- This is a barrier ---");
    });
    
    // Enqueue five more blocks
    for (int index = 5; index < 10; ++index) {
        dispatch_async(queue, ^{
            [self printNumber:index];
        });
    }
    
    dispatch_resume(queue);
}

打印結(jié)果如下

// 此處簡略描述: 一共50行, 打印0到5之間(0, 1, 2, 3, 4)的數(shù)字
--- This is a barrier ---
// 此處簡略描述: 一共50行, 打印5到10之間(5, 6, 7, 8, 9)的數(shù)字

再參照上一節(jié)描述的概念, 相信你這下肯定能理解barrier的含義了

應(yīng)用

說了這么多, 解釋的也夠清楚了, 但是為什么要有barrier GCD這兩個接口呢? 它們有哪些應(yīng)用呢?

從上面的例子, 其實已經(jīng)可以看出些"端倪", 那就是用barrier實現(xiàn): 讀-寫鎖

讀-寫鎖有以下幾個特點

  • 在沒有寫操作的時候, 可以任意的并發(fā)讀取

  • 在所有讀操作完成后, 才進行寫操作, 但是寫操作不可以并發(fā), 且在寫操作過程中, 不能讀取

  • 在寫操作完成后, 又可以任意的并發(fā)讀取了

如果我們使用barrier GCD接口來處理寫操作, 使用普通的GCD接口來并發(fā)讀取, 那么完全滿足讀-寫鎖的以上特點

廢話說到這, 最后來看例子吧

static NSString *he = @"Luke";
static NSString *she = @"Megan";

@interface ViewController ()

@property (nonatomic, strong) dispatch_queue_t queue;

@end

@implementation ViewController

- (IBAction)button1OnClicked:(UIButton *)sender {
    self.queue = dispatch_queue_create("Reader-writer queue", DISPATCH_QUEUE_CONCURRENT);
    
    for (int index = 0; index < 5; ++index) {
        dispatch_async(self.queue, ^{
            [self printAndRepeat];
        });
    }
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        dispatch_barrier_async(self.queue, ^{
            he = @"Don";
            she = @"Alice";
        });
    });
}

- (void)printAndRepeat {
    NSLog(@"%@ likes %@!", he, she);
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self printAndRepeat];
    });
}

@end

打印結(jié)果如下

Luke likes Megan!
Luke likes Megan!
......
// 過了5秒后
Don likes Alice!
Don likes Alice!
......

參考

更多文章, 請支持我的個人博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 多線程概念 線程線程指的是:1個CPU執(zhí)行的CPU命令列為一條無分叉路徑 多線程這種無分叉路徑不止一條,存在多條即...
    我系哆啦閱讀 656評論 0 5
  • 簡介 GCD(Grand Central Dispatch)是在macOS10.6提出來的,后來在iOS4.0被引...
    sunmumu1222閱讀 955評論 0 2
  • 一. 重點: 1.dispatch_queue_create(生成Dispatch Queue) 2.Main D...
    BestJoker閱讀 1,683評論 2 2
  • 目錄(GCD): 關(guān)鍵詞 混淆點 場景應(yīng)用 總結(jié) 1. 關(guān)鍵詞 線程概念: 獨立執(zhí)行的代碼段,一個線程同時間只能執(zhí)...
    Ryan___閱讀 1,370評論 0 3
  • [TOC] 第一個Java程序 前言 做IT行業(yè)也有些年頭了,玩過c/c++,看過lua,python,html/...
    恒源賓館閱讀 294評論 0 1

友情鏈接更多精彩內(nèi)容