Swift3.0 gcd学习(2)
来源:互联网 发布:战舰世界莫洛托夫数据 编辑:程序博客网 时间:2024/05/21 06:35
Swift3.0 gcd学习(2)
上一篇简单梳理了下gcd的基础概念和一些基本的使用方法。这一篇希望再深入研究下gcd的一些玩法,主要介绍在gcd里,怎样保证线程同步,有错误希望大家指正。
demo git地址
调度屏障barrier
有时会在一个并发的队列里读写一个数据对象,但如果对象并非线程安全,就会出现资源抢占的问题。之前使用dispatch_barrier_async来解决这个问题,在swift3.0,被搬到了DispatchWorkItem的flags属性中:
let workItemA = DispatchWorkItem(qos: DispatchQoS.default, flags: DispatchWorkItemFlags.barrier) { for i in 0...5 { print("barrier workItem block: ", i); } } let workItemB = DispatchWorkItem() { for i in 0...5 { print("workItem block: ", i); } } let u = DispatchQueue(label: "com.justin.barrierAsync", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.workItem, target: nil); u.async { for i in 0...5 { print("block 1: ", i); } } u.async(execute: workItemA); u.async { for i in 0...5 { print("block 2: ", i); } }
workItemB只做最普通的并发操作,输出结果如下:
block 1: 0workItem block: 0block 2: 0block 1: 1workItem block: 1block 2: 1block 1: 2workItem block: 2block 2: 2block 1: 3workItem block: 3block 2: 3block 1: 4workItem block: 4block 2: 4block 1: 5workItem block: 5block 2: 5
可以看出,三个block交错运行
下面我们换成workItemA,注意这个workItem的flag设置成了DispatchWorkItemFlags.barrier
block 1: 0block 1: 1block 1: 2block 1: 3block 1: 4block 1: 5barrier workItem block: 0barrier workItem block: 1barrier workItem block: 2barrier workItem block: 3barrier workItem block: 4barrier workItem block: 5block 2: 0block 2: 1block 2: 2block 2: 3block 2: 4block 2: 5
可以看出barrier确保提交的block是指定队列中,在特定时段唯一在执行的一个。只有在所有先于barrier的block都完成的情况下barrier block才开始执行,并且确保队列在此过程不会执行其它block。闭包完成后队列恢复。需要注意barrier只在自己创建的队列上有这种作用。
信号
另一种解决资源抢占问题的方法,就是使用信号。简单来说信号就是控制访问资源的数量,假设系统有10个资源,每个线程进入执行代码时占用一个资源,执行完成后,释放资源。当这10个线程的资源都没被释放时,第11个线程想要进入,就会被挡在外面。
声明一个信号:
let s = DispatchSemaphore(value: 2);
降低一个信号量:
s.wait();
增加一个信号量:
s.signal();
当信号量为0时,进程就会被阻塞,可以理解为资源被占完,其它线程想要入场,只能等待。一言不合上代码:
let s = DispatchSemaphore(value: 2); let g = DispatchQueue.global(); g.async { s.wait(); for i in 0...5 { print("block 1: ", i); } s.signal(); } g.async { s.wait(); for i in 0...5 { print("block 2: ", i); } s.signal(); } g.async { s.wait(); for i in 0...5 { print("block 3: ", i); } s.signal(); }//输出结果block 2: 0block 1: 0block 2: 1block 1: 1block 2: 2block 1: 2block 2: 3block 1: 3block 2: 4block 1: 4block 2: 5block 1: 5block 3: 0block 3: 1block 3: 2block 3: 3block 3: 4block 3: 5
可以看出,因为信号对象声明时,只设置了2个信号量,所以当block1和block2进入执行代码后,block3就被挡在了外面,直到前面两个block把信号量释放出来后, block3才开始执行。
所以,在一些并发队列里处理一些非线程安全的数据时,可以这么干:
let g = DispatchQueue.global(); let s = DispatchSemaphore(value: 1); var arr:[Int] = []; for i in 0...100 { g.async { s.wait();//#1 arr.append(i); s.signal();//#2 } }
如果你把上面代码#1,#2注释掉,就会出现:
fatal error: UnsafeMutablePointer.deinitialize with negative countfatal error: UnsafeMutablePointer.deinitialize with negative count
- Swift3.0 gcd学习(2)
- Swift3.0 gcd学习(1)
- Swift3.0 gcd学习(3)
- Swift3.0学习之GCD
- swift3.0 GCD
- swift3.0 gcd 变化
- swift3.0 GCD
- swift3.0 gcd 变化
- IOS GCD Swift3.0
- swift学习笔记 - swift3.0用GCD实现计时器
- Swift3.0--GCD
- swift3.0 GCD DispatchSourceTimer注意事项
- Swift3.0 GCD多线程详解
- swift3.0+GCD小小的尝试
- Swift3.0中GCD定时器的使用
- [绍棠_Swift] Swift3.0中的GCD
- Swift3.0学习
- swift3中的多线程GCD
- H5表格标准结构
- Spark -1:入门概述
- 《汇编语言》学习(十七)键盘输入和磁盘读写
- 6、打印 5 2 0 + 1 3 1 4 -------------------- 1 8 3 4
- Loadrunner 接口测试
- Swift3.0 gcd学习(2)
- 解决百度网盘等软件无法联网但是浏览器可以上网的问题
- [精华] 初识Tornado:一个简单例子
- SecureCRT安装与使用
- 对元音个数进行统计,按下回车符退出
- poj 1082 Calendar Game 博弈递推
- cocoa各种图片格式转换
- PTA--双向链表模拟Deque
- AlertDialog最基本应用