多线程
一,什么是线程?
1个进程可以开启多个线程,每个线程可以同时执行不能的任务。进程->车间。线程-> 车间工人
二,多线程的意义?
多线程优点:1.能适当的提高程序的并行执行效率
2.能适当的提高CPU/内存的利用效率
多线程缺点:1.开启线程需要占用一定的内存空间,如果开启大量的线程会占用大量的内存空间,降低程序的性能
2. 线程越多,CPU在调度线程上的开销就越大。CPU会在各个线程之间调度,CPU消耗大量资源,最后会累死,线程执行效率也会降低。
三,常见的多线程方案
实现方案 | 简介 | 生命周期 |
pthread |
1.一套通用的多线程API,适用于linux/windows/unix 等操作系统 2.可移植/跨平台,是一套纯C的 |
程序员自己管理 |
NSThread | 面向对象的,简单已用,OC语言 | 程序员自己管理 |
GCD |
旨在替代NSThread等线程技术 充分利用设备的多核 |
系统自动管理 |
NSOperation | 基于GCD,可以设置一次执行的线程的次数 | 系统自动管理 |
GCD常用的术语:
同步与异步:能不能开启新的线程
- 同步:在当前线程执行任务,不具备开启新线程的能力
- 异步:在新的线程中执行任务,具备开启新线程的能力
串行于并行的主要影响:任务的执行方式
- 串行:一个一个的按顺序执行任务
- 并行:多个任务并发的执行即多个任务同时执行
记住:使用同步函数(aysc)往当前串行队列添加任务,会卡住当前的串行队列,产生死锁。
四,多线程的安全隐患
4.1 资源共享
- 多个线程同时访问同一个对象,同一个文件,同一个
- 多个线程访问同一块资源
4.2当多个线程访问同一块资源时,很容易引发数据错误与数据安全的问题
五,多线程安全隐患的解决方案
解决方案:同步技术即协同步调,按预定的先后次序进行,常用的技术就是加锁
5.1 OSSpinLock:自旋锁
- 使用的时候导入头文件#import <libkern/OSAtomic.h>
- 等待锁的线程一直处于忙等状态,一直占着cpu的资源,目前已经不再安全,会出现优先级反转的问题
- 如果等待锁的优先级较高,他就会一直占着cpu的资源,优先级低的线程无法释放锁
- 目前已使用oss_unfair_lock替代,但是它的底层并不是一直处于忙等而是休眠状态,使用需要导入#import <os/lock.h>
- GNUstep 吧OC的Cocoa框架重新实现了一遍,有一定的参考价值。
5.2 pthread_mutex:互斥锁
- 等待锁的线程处于休眠状态,这是跨平台的一把锁。
- 使用需要导入#import <pthread.h>头文件
-
初始化设置类型的时候有递归锁,默认锁,这些锁都需要手动销毁
-
pthread_mutex-条件锁 初始化的时候设置条件,也许要手动销毁
5.3 NSLock 是对pthread_mutex普通锁的封装,更加的面向对象。
NSRecursive 是对pthread_mutex递归锁的封装
NSCondtion 是对pthread_mutex 条件锁的封装
NSCondtionLock是对 NSCondtion锁的进一步封装可以设置具体的条件值。
5.4信号量dispatch_semaphore
信号量的初始值可以用来控制线程并发的最大数量,初始值代表同时只允许几条线程进行访问,保证线程同步。
5.5 @synchronized 可以参考objc4中的objc-sync.mm文件 也是对递归锁的封装
线程同步方案:性能从高到低排序
1 os_unfair_lock ;2 OSSpinLock ;3 dispatch_semaphore; 4 pthread_mutex; 5 dispatch_queue(DISPATCH_QUEUE_SERIAL)
6 NSLock ;7 NSCondition ;8 pthread_mutex(recursive); 9 NSRecursiveLock ;10 NSConditionLock ;11 synchronized
五,自旋锁与互斥锁的的区别
1.什么情况下使用互斥锁比较划算?
- 预计线程等待的锁的时间较长
- 单核处理器
- 临界区(指的是访问共用资源,这些资源又无法同时被多个进程访问的特性)有IO操作
- 临界区竞争非常激烈,且代码复杂或者循环量大
2.什么情况下使用自旋锁比较划算?
- 预计线程等待的锁的时间短
- 多核处理器
- CPU竞争不紧张。加锁的代码经常被调用
- 临界区竞争非常激烈,且代码复杂或者循环量大