iOS开发 之 barrier GCD

本文Demo的完整工程代码, 参考这里的GCDDemo

目录

引言

GCD是iOS开发中一个"老生常谈"的话题了, 例如之前的几篇文章

但是最近在阅读SDWebImage源码时(详见iOS开发 之 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两种, 其中系统为我们创建的serial queue通过dispatch_get_main_queue来获取, concurrent queue通过dispatch_get_global_queue来获取

  • GCD的queue与thread并无直接映射关系, async的block可能在子线程也有可能在ui thread中执行(详见iOS开发 之 Queue和Thread), 这也是GCD的价值所在, 让开发者关注队列而非线程

  • GCD的async接口, 将block添加到queue后会立即返回, 而sync接口与async正好相反, 将block添加到queue后直到block执行结束后才返回

  • 在当前线程中调用sync接口, 会引起死锁(详见iOS开发 之 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的区别), 所以本文重点讨论其中的一个接口

很多文章对官方解释做了详尽的翻译(例如可以参考Dispatch_barrier_async的研究), 而我更习惯于提炼其中的几个要点如下

  • 通过dispatch_barrier_async添加的block会等到之前添加所有的block执行完毕再执行

  • 在dispatch_barrier_async之后添加的block会等到dispatch_barrier_async添加的block执行完毕再执行

  • dispatch_barrier_async的上述特点只在自己创建的concurrent queue有效, 在serial queue和global concurrent queues中的作用和dispatch_sync完全相同

虽说是要点, 但是怎么感觉还是有点绕啊, 没关系, 重点来了

请问barrier的含义是? 没错, 这个确实是重点

barrier: 障碍物, 屏障, 界线

知道了barrier的含义, 理解dispatch_barrier_async就变得很轻松了:

以barrier为分界, 前面的执行完才能执行后面的

例子

概念介绍完了, 如果你还没理解的话, 也没关系, 我们来看下面的例子

- (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);
}

打印结果如下

// 此处简略描述: 一共50行, 打印0到5之间(0, 1, 2, 3, 4)的数字
--- This is a barrier ---
// 此处简略描述: 一共50行, 打印5到10之间(5, 6, 7, 8, 9)的数字

再参照上一节描述的概念, 相信你这下肯定能理解barrier的含义了

应用

说了这么多, 解释的也够清楚了, 但是为什么要有barrier GCD这两个接口呢? 它们有哪些应用呢?

从上面的例子, 其实已经可以看出些"端倪", 那就是用barrier实现: 读-写锁

读-写锁有以下几个特点

  • 在没有写操作的时候, 可以任意的并发读取

  • 在所有读操作完成后, 才进行写操作, 但是写操作不可以并发, 且在写操作过程中, 不能读取

  • 在写操作完成后, 又可以任意的并发读取了

如果我们使用barrier GCD接口来处理写操作, 使用普通的GCD接口来并发读取, 那么完全满足读-写锁的以上特点

废话说到这, 最后来看例子吧

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

打印结果如下

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

参考

更多文章, 请支持我的个人博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 多线程概念 线程线程指的是:1个CPU执行的CPU命令列为一条无分叉路径 多线程这种无分叉路径不止一条,存在多条即...
    我系哆啦阅读 576评论 0 5
  • 简介 GCD(Grand Central Dispatch)是在macOS10.6提出来的,后来在iOS4.0被引...
    sunmumu1222阅读 858评论 0 2
  • 一. 重点: 1.dispatch_queue_create(生成Dispatch Queue) 2.Main D...
    BestJoker阅读 1,582评论 2 2
  • 目录(GCD): 关键词 混淆点 场景应用 总结 1. 关键词 线程概念: 独立执行的代码段,一个线程同时间只能执...
    Ryan___阅读 1,264评论 0 3
  • [TOC] 第一个Java程序 前言 做IT行业也有些年头了,玩过c/c++,看过lua,python,html/...
    恒源宾馆阅读 241评论 0 1