a) GCD的队列可以分为2大类型
1) 并发队列(Concurrent Dispatch Queue)
1.1) 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
1.2) 并发功能只有在异步(dispatch_async)函数下才有效
b) 串行队列(Serial Dispatch Queue)
1) 让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
2) 主队列是一种特殊的串行队列
c) 队列的特点 : 排队,FIFO,First In First Out 先进先出
d) Global Queue全局队列的指针地址是相同的,而手动创建的队列则地址是不相同的
4.容易混淆的术语
a) 同步和异步主要影响:能不能开启新的线程
1) 同步:在当前线程中执行任务,不具备开启新线程的能力
2) 异步:在新的线程中执行任务,具备开启新线程的能力
b) 并发和串行主要影响:任务的执行方式
1) 并发:多个任务并发(同时)执行
2) 串行:一个任务执行完毕后,再执行下一个任务
5.各种队列的执行效果
a) 使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(产生死锁)
b) performSelector:withObject:afterDelay:1) 有afterDelay的方法都是跟Runloop有关,相当于添加了一个定时器到Runloop去执行 所以你要看当前执行任务的线程有没有Runloop
2) 在主线程好时正常调用,但是会延迟,因为主线程默认就会开启一个Runloop,延迟是因为主线程的任务执行顺序是串行的,需要等上一个任务执行完毕,可以理解为包装该线程调用的{}范围函数调用完毕,例如viewDidLoad方法调用完毕
3) 但是在子线程却不好使,直接不调用,因为子线程没有开启Runloop来保活
6.队列组的使用
a) 思考:如何用gcd实现以下功能
1) 异步并发执行任务1、任务22) 等任务1、任务2都执行完毕后,再回到主线程执行任务3
7.多线程的安全隐患
a) 资源共享
1)1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源
2) 比如多个线程访问同一个对象、同一个变量、同一个文件
b) 当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题
c) 多线程安全隐患示例01 – 存钱取钱
a) 什么情况使用自旋锁比较划算?
1) 预计线程等待锁的时间很短
2) 加锁的代码(临界区)经常被调用,但竞争情况很少发生
3) CPU资源不紧张
4) 多核处理器
b) 什么情况使用互斥锁比较划算?
1) 预计线程等待锁的时间较长
2) 临界区有IO操作
3) 临界区代码复杂或者循环量大
4) 临界区竞争非常激烈
5) 单核处理器
c) 临界区:lock与unlock之间的代码
d) IO操作:文件操作(读和写的操作)
11.atomic
a) atomic用于保证属性setter、getter的原子性操作,相当于在getter和setter内部加了线程同步的锁
b) 可以参考源码objc4的objc-accessors.mm
c) 它并不能保证使用属性的过程是线程安全的
12.iOS中的读写安全方案
a) 思考如何实现以下场景
1) 同一时间,只能有1个线程进行写的操作
2) 同一时间,允许有多个线程进行读的操作
3) 同一时间,不允许既有写的操作,又有读的操作
b) 上面的场景就是典型的“多读单写”,经常用于文件等数据的读写操作
c) iOS中的实现方案有
1) pthread_rwlock:读写锁
a) GNUstep是GNU计划的项目之一,它将Cocoa的OC库重新开源实现了一遍
b) 源码地址:http://www.gnustep.org/resources/downloads.php
c) 虽然GNUstep不是苹果官方源码,但还是具有一定的参考价值
14.其它知识点总结
a) lldb查看汇编指令级别代码时一行一行的运行
1)stepi(si)2)nexti(ni):也是一行一行,但是遇到函数调用会一笔带过这个函数调用
3) c:直接跳到下一个断点
b) 定义变量的时候同时给他赋值结构体可以这么干,但是不能直接给结构体赋值
c) 线程的任务一旦执行完毕,生命周期就结束了,无法再使用 // 准确来讲,使用runloop是为了让线程保持激活状态