2.1 进程和线程
2.1.1 进程的概念、组成、特征
1 、进程的概念
在多道程序环境下,允许多个程序并发执行,此时它们将失去封闭性,并具有间断性及不可再现性的特征。
封闭性:一个进程一旦开始执行,其执行结果就只取决于它本身,不受外界因素影响。在封闭性下,进程的执行速度都不会改变它的执行结果。
失去封闭性后,不同速度下的执行结果不同。
程序:是静态的,就是个存放在磁盘里的可执行文件,就是一系列的指令集合。
进程:是动态的,是程序的一次执行过程---->同一个程序多次执行会对应多个进程 (如:在一台电脑上打开多个QQ,则在任务管理器中显示多个)
引入进程的目的:
更好地使多道程序并发执行,提高资源利用率和系统吞吐量。
多角度定义:
- 进程是程序的一次执行过程
- 进程是一个程序及其数据在处理机上顺序执行时所发生的活动
- 进程是具有独立功能的程序在一个数据集合上运行的过程,是系统进行资源分配和调度的一个独立单位。
2、 进程的组成–PCB
操作系统为了区分各个进程(因为有时候对同一个程序打开多次,就是不同的进程),所以当进程被创建时,操作系统会为该进程分配一个唯一的、不重复的“身份证号”–PID(进程标识符)
3、 进程的组成–程序段、数据段
程序的执行
进程的组成
PCB是进程存在的唯一标志!!!
4、 进程的特征
进程之间可能是无关的,但也可能是有交互的。
小结:
2.1.2 进程的状态与转换、进程的组织
1、进程的状态–创建态、就绪态
2、进程的状态–运行态
一个进程正在运行,意味着CPU在执行该进程对应的程序(执行指令序列)
3、进程的状态–阻塞态
当对应的打印机资源空闲时,可以让对应的进程2从阻塞态转变为就绪态
4、进程的状态–终止态
通常用户进程被建立后,随着进程运行的正常或不正常结束而撤销。
5、进程状态的转换
在任何时刻,一个进程的状态变化不一定会引起另一个进程的状态变化。
如:处于运行态的进程如果进行“系统调用”,会变成阻塞态,会导致另一个进程由就绪态变为运行态。
处于阻塞态的进程转变为就绪态时不会导致其他进程变化。
6、进程的状态
进程PCB中,会有一个变量state来表示进程的当前状态。
为了对统一个状态下的各个进程进行统一的管理,操作系统会将各个进程的PCB组织起来------>进程的组织
7、进程的组织
(1)链接方式
很多操作系统还会根据阻塞原因不同,在分为多个阻塞队列
如:
(2)索引方式
小结:
2.1.3 进程控制
1、概念
2、如何实现进程控制
——>用“原语”实现
原语的执行具有“原子性”,一气呵成。因为如果不能“一气呵成”,就有可能导致操作系统中的某些关键数据结构信息不统一的情况,这会影响操作系统进行别的管理工作。
3、如何实现原语的“原子性”
利用“关中断指令“和”开中断指令“这两个特权指令来实现原子性。
正常情况下:CPU每执行完一条指令就会例行检查中断信号
但是:在执行关中断指令后,CPU就不再检查中断信号,直到执行开中断指令之后才恢复检查,才对之前没有处理的中断信号进行处理
这样——,关中断、开中断之间的指令序列就实现了“原子性”
4、进程控制相关的原语(创建、终止、阻塞和唤醒)
为新进程分配所需的资源一般为:内存、文件、I/O设备、CPU时间等。
小结:
2.1.4 进程通信
进程间通信(IPC)是指两个进程之间产生数据交互。
(如:在微博界面转发一条微博可以到微信上)
进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立。
出于安全考虑,一个进程不能直接访问另一个进程的地址空间。
所以进程通信需要操作系统支持。
1、共享存储
为避免出错,各个进程对共享空间的访问应该是互斥的。
各个进程可使用操作系统内核提供的同步互斥工具(如P、V操作)
2、消息传递
进程间的数据交换以格式化的消息为单位。进程通过操作系统提供的“发送消息/接收消息”两个原语进行数据交换。
直接通信方式
间接通信方式(信箱通信方式)
进程P通过系统调用申请两个信箱A B
指明的是发送到哪个信箱,不是指明哪个进程
3、管道通信
数据的读写是FIFO(先进先出)
小结:
2.1.5 线程的概念
1、线程的概念
传统进程定义中,进程是程序的一次执行,但是这些功能显然不可能是由一个程序顺序处理就能实现的。
- 可以把线程理解为“轻量级进程”。
- 线程是一个基本的CPU执行单元,也是程序执行流的最小单位。
- 引入线程之后,不仅是进程之间可以并发,进程内的各线程之间也可以并发,从而进一步提升了系统的并发度,使得一个进程内也可以并发处理各种任务(如QQ视频、文字聊天、传文件)。
- 引入线程后,进程只作为除CPU之外的系统资源的分配单元(如打印机、内存地址空间等都是分配给进程的),而线程则作为处理机的分配单元。
引入进程的目的:
减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能
2、引入线程机制后的变化
3、线程的属性
- 不同的线程可以执行相同的程序,即同一个服务程序被不同的用户调用时,操作系统把它们创建成不同的线程。
- 不同进程间可以并发执行,同一个进程中的多个线程可以并发执行,甚至不同进程中的线程也能并发执行,从而使操作系统有更好的并发性,提高了系统资源的利用率和系统的吞吐量。
2.1.6 线程的实现方式和多线程模型
1、线程的实现方式
1.1 用户级线程(ULT)(又称:内核支持的线程)
历史背景:早期的操作系统只支持进程,不支持线程。当时的“线程”是由线程库实现的
- 线程的管理工作是由用户程序通过线程库来完成的。
- 线程切换不需要CPU变态,在用户态就可以完成。
- 处理机的调度对象是进程。
- 操作系统只能意识到进程的存在,不能意识到用户级线程的存在。
- 优缺点:
① 优点:用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高。
调度算法可以是进程专用的,不同的进程可根据自身的需要,对自己的线程选择不同的调度算法。
② 缺点:当一个用户级线程被阻塞后,整个进程都会被阻塞,并发性不高。多个线程不可以在多核处理机上并发运行。
1.2 内核级线程(KLT,又称“内核支持的线程”)
- 线程的管理工作是由操作系统来完成
- 线程切换需要CPU变态,由用户态转变为内核态。
- 操作系统可以意识到内核级线程的存在。
- 优缺点:
2、多线程模型
在支持内核级线程的系统中,根据用户级线程和内核级线程的映射关系,可以划分为几种多线程模型。
2.1 一对一模型
2.2 多对一模型
操作系统只“看得见”内核级线程,因此只有内核级线程才是处理机分配的单位。
2.3 多对多模型
小结:
2.1.7 线程的状态与转换(新增考点)
1、状态与转换
类比进程的转换
2、组织与控制
2.2 处理机调度
2.2.1 调度的概念、层次
1、基本概念
当有一堆任务要处理,但由于资源有限,这些事情没法同时处理。这就需要确定某种规则来决定处理这些任务的顺序,这就是“调度”研究的问题。
2、调度的三个层次
① 高级调度(作业调度)
作业-------->一个具体的任务
用户向系统提交一个作业 (近似等于) 用户让操作系统启动一个程序(来处理一个具体的任务)
② 低级调度(进程调度、处理机调度)
------>是按照某种策略从就绪队列中选取一个进程,将处理机分配给它。
进程调度是操作系统中最基本的一种调度,在一般的操作系统中都必须配置进程调度。
进程调度频率很高,一般几十毫秒一次。
③ 中级调度(内存调度)
3、补充知识:进程的挂起态与七状态模型
4、三层调度的联系、对比
小结:
2.2.2 进程调度的时机、切换与过程、方式
1、进程调度的时机
进程在 操作系统内核程序临界区 中 不能 进行调度与切换。
进程处于 临界区 时 可以 进行处理机调度。
临界资源:一个时间段内只允许一个进程使用的资源。各进程需要 互斥地 访问临界资源。
临界区:访问临界资源的那段代码。
内核程序临界区:一般是用来访问某种内核数据结构的,比如进程的就绪队列(由各就绪进程的PCB组成)
访问的是普通资源时:
2、进程调度的方式
① 非剥夺调度方式(非抢占方式)
② 剥夺调度方式(抢占方式)
3、进程的切换与过程
进程切换:指的是一个进程让出处理机,由另一个进程占用处理机的过程。
狭义的进程调度:指的是从就绪队列中选中一个要运行的进程。(这个进程可以是刚刚被暂停执行的进程,也可能是另一个进程,后一种情况就需要进程切换)
广义的进程调度:包含了选择一个进程和进程切换两个步骤。
小结:
2.2.3 调度器和闲逛进程
1、调度器/调度程序
支持内核级线程的操作系统中,内核线程作为调度的基本单位,进程作为资源分配的基本单位。
2、闲逛进程
调度程序永远的备胎,在没有其他就绪进程时,才运行闲逛进程
闲逛进程的特性:
- 优先级最低。
- 可以是0地址指令,占用一个完整的指令周期(指令周期末尾例行检查中断)。
- 能耗低。
- 不需要CPU之外的资源,不会被阻塞
2.2.4 调度算法的评价指标
1、CPU利用率
指CPU“忙碌”的时间占总时间的比例
利用率=忙碌的时间/总时间------->有的题目还会要求计算某种设备的利用率
2、系统吞吐量
指:单位时间内完成作业的数量
系统吞吐量=总共完成了多少道作业/总共花了多少时间
3、周转时间
是指从作业被提交给系统开始,到作业完成为止的这段时间间隔。
包括四部分:
- 作业在外存后备队列上等待作业调度(高级调度)的时间---->只发生一次
- 进程在就绪队列上等待进程调度(低级调度)的时间
- 进程在CPU上执行的时间
- 进程等待I/O操作完成的时间
------>后三项在一个作业的整个处理过程中,可能发生多次
4、等待时间
指进程/作业 处于等待处理机状态时间之和,等待时间越长,用户满意度越低。
5、响应时间
小结:
2.2.5 调度算法
1、先来先服务(FCFS)
2、短作业优先(SJF)
(Shortest Job First)
例子:
非抢占式:
抢占式:
注意点:
对比FCFS和SJF
3、高响应比优先(HRRN)
(Highest Response Ratio Next)
例子:
小结:
1、时间片轮转(RR)
(Round-Robin)
时间片轮转调度算法常用于分时操作系统,更注重“响应时间”
时间片长短的确定因素:
- 系统的响应时间
- 就绪队列中的进程数目
- 系统的处理能力
例子:
2、优先级调度算法
例子:
非抢占式:
抢占式:
补充:
I/O繁忙型与CPU繁忙型作业
时间片轮转调度算法------->利于I/O繁忙型作业
先来先服务调度算法------->利于CPU繁忙型作业
短作业(进程)优先算法---->利于I/O繁忙型作业
优先权调度算法------------->利于I/O繁忙型作业
3、多级反馈队列调度算法
设计多级反馈队列队列调度算法时需要考虑的是:
- 就绪队列的数量
- 就绪队列的优先级
- 各就绪队列的调度算法
- 进程在就绪队列间的迁移条件
例子:
小结:
1、多级队列调度算法
2.3 同步与互斥
2.3.1 进程同步、进程互斥
1、进程同步
2、进程互斥
对临界资源的互斥访问,可以在逻辑上分为如下四部分:
- 进入区
- 临界区
- 退出区
- 剩余区
小结:
2.3.2 进程互斥的软件实现方法
1、单标志法
算法思想:
两个进程在 访问完临界区后 会把使用临界区的权限转交给另一个进程。也就是说 每个进程进入临界区的权限只能被另一个进程赋予。
类比记忆:
2、双标志先检查法
类比记忆:
3、双标志后检查法
类比记忆:
4、Peterson算法
类比例子:
如:1 6 2 7 8…
可以先利用例子推导,在利用代码分析。
谁最后说了“客气话”,谁就失去了行动的优先权。
(就是谁最后设置的turn值,就是那个进程没有优先权)
场景一: 场景二:
结论:
小结:
2.3.3 进程互斥的硬件实现方法
通过硬件支持实现临界段问题的方法称为 低级方法,或称为 元方法。
1、中断屏蔽方法
2、TestAndSet指令(TSL指令)
3、Swap指令
小结:
2.3.4 互斥锁(新考点)
1、进程互斥:锁
2.3.5信号量机制
1、整型信号量
用一个 整数型的变量作为信号量,用来表示系统中某种资源的数量。
------> 与普通整数变量的区别:对信号量的操作只有三种,即初始化、p操作、v操作
2、记录型信号量
例子:初始时S.value=2,S.L=null
进程在使用前用wait原语申请资源,然后用signal原语释放资源
如果开始CPU为P0服务,先执行S.value–,S.value变为1,系统将一个打印机资源分配给P0
然后到P1进程,先执行S.value–,S.value变为0,系统将一个打印机资源分配给P1
接下来CPU到P2进程,先执行S.value–,S.value = -1,进程主动执行block原语,让进程从运行态变为阻塞态,P2进程挂到打印机资源的等待队列里
接下来CPU为P3进程服务,然后value变为-2,进程P3挂到等待队列中
假设接下来CPU为P0服务
则进行signal原语,value++,变为-1,<0,说明有进程在等待该资源,使用wakeup原语唤醒等待队列中的第一个进程P2,P2从阻塞态变为就绪态
CPU对P2操作,S.value++,变为0,=0,说明有进程在等待该资源,使用wakeup原语唤醒等待队列中的第一个程序P3,P3从阻塞态变为就绪态
然后CPU回到P1进程,S.value++,变为1,>0,说明没有进程在等待该资源,
系统回收资源
然后CPU到P3进程,S.value++,变为2,系统回收资源,结束
总结:
小结:
2.3.6 用信号量实现进程互斥、同步、前驱关系
1、实现进程互斥
2、实现进程同步
回忆:什么是进程同步:
假设代码4必须在代码1 2之后,则:
上述例子中的“前操作”即是代码1和代码2,然后在它们之后执行V(S)
“后操作”即是代码4,在它之前执行P(S)
3、实现进程的前驱关系
小结:
2.3.7 生产者-消费者问题
问题描述:
相当于同步问题
1、PV操作题目分析步骤
1、关系分析
找出题目中描述的各个进程,分析它们之间的同步、互斥关系
缓冲区满时,生产者必须等待
当消费者进程从缓冲区取走数据后,如果有生产者进程是处于阻塞态的,那么消费者进程要把生产者进程重新唤醒,让它重新进入就绪态
但是不代表生产者进程立即向缓冲区写数据!!!
缓冲区空时,消费者必须等待
2、整理思路
根据各进程的操作流程确定P、V操作的大致顺序
③ 互斥关系的实现:设置互斥信号量mutex,在进入缓冲区前执行P(mutex),在退出缓冲区后执行V(mutex)
3、设置信号量
根据题目条件确定信号量的初值(互斥信号量初值一般为1,同步信号量的初始值要看对应资源的初始值是多少)。
- full,消费者进程在消费之前是要申请一个产品,所以full应该对应产品数量,即非空缓冲区的数量,初始为0。
- empty,生产者进程每生产一个产品要消耗一个缓冲区,所以empty对应的是空闲缓冲区数量,初始为n。
4、代码实现
2、能否改变相邻P、V操作顺序
逻辑上没问题,但是实际会对系统效能产生影响,不建议放
小结:
2.3.8 多生产者-多消费者问题
多–>指的是多类
问题描述:
1、PV操作题目分析步骤
1、关系分析
找出题目中描述的各个进程,分析它们之间的同步、互斥关系
互斥关系:
对缓冲区(盘子)的访问要互斥地进行
同步关系(一前一后):
- 父亲将橘子放入盘子后,女儿才能取苹果
- 母亲将橘子放入盘子后,儿子才能取橘子
- 只有 盘子为空 时,父亲或母亲才能放入水果。
----->“盘子为空”这个事件可以由儿子或女儿触发,事件发生后才允许父亲或母亲放水果。
2、整理思路
根据各进程的操作流程确定P、V操作的大致顺序
互斥:在临界区前后分别PV
同步:前V后P
3、设置信号量
根据题目条件确定信号量的初值(互斥信号量初值一般为1,同步信号量的初始值要看对应资源的初始值是多少)。
4、代码实现
当不设置专门的互斥变量mutex时
也不会出现多个进程同时访问盘子的现象
如果盘子(缓冲区)容量为2
小结:
2.3.9 吸烟者问题
问题描述:
本质上也是“生产者-消费者”问题,更详细的说应该是“可生产多种产品的单生产者-多消费者”
1、PV操作题目分析步骤
1、关系分析
找出题目中描述的各个进程,分析它们之间的同步、互斥关系
2、整理思路
根据各进程的操作流程确定P、V操作的大致顺序
互斥:在临界区前后分别PV
同步:前V后P
3、设置信号量
根据题目条件确定信号量的初值(互斥信号量初值一般为1,同步信号量的初始值要看对应资源的初始值是多少)。
不设置互斥信号量(因为缓冲区为1,可以省略)
4、代码实现
小结:
2.3.10 读者写者问题
问题描述:
②③④总结:当一个写进程要写时,要等到其他操作都结束才可以
1、关系分析
找出题目中描述的各个进程,分析它们之间的同步、互斥关系
两类进程:写进程、读进程
互斥关系:写进程–写进程、写进程–读进程。读进程与读进程不存在互斥问题
2、整理思路
根据各进程的操作流程确定P、V操作的大致顺序
3、设置信号量
根据题目条件确定信号量的初值(互斥信号量初值一般为1,同步信号量的初始值要看对应资源的初始值是多少)。
4、代码实现
所以引用count变量
看似可以,但是也是存在问题
当读者1执行完代码①判断可以进程代码②,这个时候读者2也进行判断,发现也可以执行代码①,接着执行代码②,执行完后rw值=0,这个时候要是在切换到读者1时,它会被阻塞。
还是存在潜在问题:
只要有读进程还在读,写进程就要一直被阻塞等待,可能出现“饿死”。因此,这种算法中,读进程是优先的
需要在设置一个互斥信号量w,用于实现“写优先”
小结:
2.3.11 哲学家进餐问题
问题描述:
1、关系分析
2、整理思路
3、信号量设置
4、代码实现
情况一:
情况二
如何防止死锁的发生
①假设0号取筷子,在执行到第二步后,如果2号执行,则被阻塞
②假设0号执行到吃饭步骤,这个时候1号也想去吃饭,然后被阻塞在第二个代码上,这个时候2号开始,先执行代码一,因为1号执行了第一句,所以2号也必须等待,即使这个时候它两边有筷子。
③假设0号执行到吃饭,之后4号执行到拿左的筷子,但是会堵塞到拿右筷子步骤
------>此时4号右边的筷子不可用,但4号仍然会先拿起左边的筷子
小结:
2.3.12 管程
1、为什么引入管程
因为信号量机制存在编写程序困难、易出错问题
管程---->一种高级同步机制
2、管程的定义和基本特征
管程和PV操作一样,也是用来实现进程的互斥和同步
3、用管程解决生产者消费者问题
小结:
2.4 死锁
2.4.1 死锁的概念
1、死锁
哲学家进餐问题
2、死锁、饥饿、死循环的区别
3、死锁产生的必要条件
4、什么时候会发生死锁
5、死锁的处理策略
小结:
2.4.2 预防死锁
只要破坏死锁产生的四个必要条件之一,死锁就不会发生
1、破坏互斥条件
互斥条件:只有对必须互斥使用的资源的争抢才会导致死锁
2、破坏不剥夺条件
不剥夺条件:进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。
3、破坏请求和保持条件
请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。
4、破坏循环等待条件
循环等待条件:存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。
小结:
2.4.3 避免死锁(银行家算法)
1、什么是安全序列
例子:
问题:
此时手中还有40亿
情况1:B还想借走30亿
不可以借
情况2:A想借20亿
用上述方法分析:
可以答应,
2、银行家算法
在BAT上述例子中,只有一种类型的资源-钱,但在计算机系统中有更多的资源,应该怎么拓展?
---------->
进行分析:
如何判断系统是否处于安全状态?----->尝试找出一个安全序列
依次检查剩余可用资源(3,3,2)是否能满足各进程的需求
方法一:
将P1加入安全序列,并更新剩余可用资源值为(5,3,2)
方法二:
找不到安全序列的例子:
如何用代码实现
如进程P0申请资源(2,1,1)
步骤③执行后会改变相关数据,如下
修改数据后执行步骤④
小结:
2.4.4 死锁的检测和解除
在死锁的检测和解除中,系统为进程分配资源时不采取任何措施,但提供死锁的检测和解除手段。
1、死锁的检测
分配边:资源结点指向进程结点
如何分配:
最终还连这边的那些进程就是处于死锁状态的进程
2、死锁的解除