一 计算机系统概述
基本构成
处理器、内存、输入/输出模块、系统总线
指令执行
取指阶段+执行阶段
指令操作分类
- 处理器-存储器
- 处理器-I/O
- 数据处理
- 控制
中断
中断是一种机制,即允许其它模块(I/O、存储器)在处理器正常处理过程中打断其工作
中断分类
-
程序中断
在某些条件下由指令执行的结果产生,如算术溢出、除数为0、试图执行一条非法机器指令及访问用户不允许的存储器位置
-
时钟中断
由处理器内部的计时器产生,允许操作系统以一定的规律执行函数
-
I/O中断
由I/O控制器产生,用于发信号通知一个操作的正常完成或各种错误条件
-
硬件失效中断
由诸如掉电或存储器奇偶校验错之类的故障产生
中断处理
多个中断如何处理
-
顺序中断处理
处理完一个中断再处理下一个
-
嵌套中断处理
定义定义中断优先级,允许高优先级的中断打断低优先级的中断处理程序的运行
存储器层次结构
从上至下
- 板上存储器,包括寄存器、高速缓存、内存
- 板外存储器,包括磁盘
- 离线存储器,包括磁带
特点
- 每“位”的价格递减
- 容量递增
- 存取时间递增
- 处理器访问的频率递减
高速缓存
处理器和内存之间的存储器
I/O操作技术
-
程序查询式I/O或者可编程I/O
I/O模块执行请求的动作并设置I/O状态寄存器中相应的位
处理器执行I/O指令后,要定期检查I/O的状态,以确定I/O操作是否已经完成
问题:处理器在等待I/O操作完成期间需不断询问I/O模块的状态,严重降低了整个系统的性能
-
中断驱动I/O
处理器给I/O模块发送I/O命令,然后继续做其它有用的工作
当I/O模块准备好与处理器交换数据时,将打断处理器的执行并请求服务
处理器执行数据传送,然后恢复以前的执行过程
问题:处理器仍需要主动干预在存储器和I/O模块之间的数据传送,任何数据传送都必须完全通过处理器
-
直接内存存取DMA
当处理器要读或写一块数据时,给DMA模块产生一条命令,发送以下信息:
是否请求一次读或写;
涉及的I/O设备的地址;
开始读或写的存储器单元;
需要读或写的字数。
处理器继续其它工作。DMA模块直接与存储器交互,传送整个数据块,无须处理器参与;
传送完成,DMA模块发一个中断信号给处理器。
问题:在DMA传送过程中,当处理器需要访问总线时,因存在竞争,处理器将暂停一个总线周期,处理器的执行速度会变慢
二 操作系统概述
操作系统的目标
-
方便
使计算机更易于使用
-
有效
允许以更有效的方式使用计算机系统资源
-
扩展能力
允许在不妨碍服务的前提下,有效地开发、测试和引入新的系统功能
操作系统提供的服务
- 程序开发
- 程序运行
- I/O设备访问
- 文件访问控制
- 系统访问
- 错误检测和响应
- 记账
典型计算机系统中三种重要接口
- 指令系统体系结构ISA
- 应用程序二进制接口ABI
- 应用程序编程接口API
操作系统开发的4个重要理论进展
- 进程
- 内存管理
- 信息保护和安全
- 调度和资源管理
现代操作系统的特征
- 微内核体系结构
- 分布式操作系统
- 多线程
- 面向对象设计
- 对称多处理
三 进程描述和控制
进程定义
- 一个正在执行中的程序
- 一个正在计算机上执行的程序实例
- 能分配给处理器并由处理器执行的实体
- 一个具有以下特征的活动单元:一组指令序列的执行 、一个当前状态和相关的系统资源集
构成进程的基本元素
程序代码、数据集
进程控制块组成
-
标识符
跟这个进程相关的唯一标识符,用来区别其他进程
-
状态
进程当前的状态
-
优先级
相对于其他进程的优先级
-
程序计数器
程序中即将被执行的下一条指令的地址
-
内存指针
包括程序代码和进程相关数据的指针,还有和其他进程共享内存块的指针
-
上下文数据
进程执行时处理器的寄存器中的数据
-
I/O状态信息
包括显式的I/O请求、分配给进程的I/O设备和被进程使用 的文件列表等
-
记账信息
可能包括处理器时间总和、使用的时钟数总和、时间限制、 记账号等
进程创建方式
- 新批处理作业提交给操作系统
- 交互系统终端用户登录到系统
- 操作系统创建
- 进程派生
进程终止方式
- 正常完成
- 超过时限
- 无可用内存
- 超出范围
- 保护错误
- 算术错误
- 时间超出
- I/O失败
- 无效指令
- 特权指令
- 数据误用
- 操作员或操作系统干涉
- 父进程终止
- 父进程请求
进程状态
两状态进程模型
五状态进程模型
七状态进程模型
挂起:操作系统将进程从内存换出到外存的过程
进程挂起的原因
- 交换
- 其他OS原因
- 交互式用户请求
- 定时
- 父进程请求
操作系统的控制结构
- 内存表
- I/O表
- 文件表
- 进程表
进程映像
- 用户数据
- 用户程序
- 栈
- 进程控制块
进程控制块组成
-
进程标识信息
进程ID、父进程ID、用户ID
-
进程状态信息
用户可见寄存器、控制和状态寄存器、栈指针
-
进程控制信息
调度和状态信息、数据结构、进程通信、进程特权、存储管理、资源的所有权和使用情况
处理器执行模式
-
用户模式/非特权模式
用户程序通常在该模式下运行
-
系统模式/控制模式/内核模式/特权模式
操作系统内核在该模式下运行
进程创建步骤
- 分配进程标识符
- 分配空间
- 初始化进程控制块
- 设置正确连接
- 创建或扩充其它数据结构
进程切换
进程切换是让处于运行态的进程中断运行,让出处理器,让操作系统指定的新进程运行。被中断进程的上下文环境需要保存
切换时机
-
中断
包括时钟中断、I/O中断、内存失效
-
陷阱
-
系统调用
模式切换
用户模式与系统模式的切换
进程切换与模式切换区别
-
模式切换可以不改变正处于运行态的进程状态, 保存和恢复上下文环境开销小
-
进程切换涉及进程状态的变化,开销较大
-
进程切换一定引起模式切换,模式切换不一定引起进程切换
四 线程
进程和线程区别
- 进程是拥有资源所有权的单位,线程是调度运行的单位
- 一个进程在其执行的过程中可以产生多个线程,基本上各进程是独立的,同一进程中的各线程不一定独立,有可能会相互影响
- 线程执行开销小,但不利于资源的管理和保护,而进程正相反
- 一个进程中可以有多个线程,多个线程共享进程的堆和方法区 (JDK1.8 之后的元空间)资源,但是每个线程有自己的程序计数器、虚拟机栈和本地方法栈
线程状态
主要状态有就绪态、运行态、阻塞态
挂起对线程没有意义
线程分类
-
用户级线程
有关线程管理的所有工作都由应用程序完成,内核意识不到线程的存在
优点
1 线程切换不需要内核态特权
2 调度可以是应用程序相关的
3 用户级线程可以在任何操作系统中运行,不需要对底层内核进行修改以支持用户级线程
缺点
1 当执行一个系统调用时,会阻塞进程中所有线程
2 无法利用多处理技术
-
内核级线程
有关线程管理的工作由内核完成,应用程序只有 一个到内核线程设施的应用程序编程接口
优点
1 内核可同时把同一进程中的多个线程调度到多个处理器中
2 若进程中的一个线程被阻塞,内核可以调度同一进程中的另一个线程
3 内核例程本身也可以使用多线程
缺点
把控制权从一个线程传送到同一个进程内的另一个线程时,需要切换内核模式
五 并发性:互斥和同步
名词解释
-
原子操作
保证指令序列要么作为一个组来执行,要么都不执行
-
临界区
一段代码,在这段代码中进程将访问共享资源,当一个进程已经在这段代码中运行时,另外一个进程就不能在这段代码中执行
-
死锁
两个或两个以上的进程因其中的每个进程都在等待其他进程做完某些事情而不能继续执行
-
活锁
两个或两个以上进程为了响应其他进程中的变化而持续改变自己的状态但不做有用的工作
-
互斥
当一个进程在临界区访问共享资源时,其他进程不能进入该临界区访问任何共享资源
-
竞争条件
多个线程或进程在读写一个共享数据时,结果依赖于它们执行的相对时间
-
饥饿
一个可运行的进程被调度程序无限期地忽略,不能被调度执行的情形
-
并发
单处理器多道程序设计系统中,进程交替执行(单CPU、多进程、交替执行)
-
并行
多处理器系统中,不仅可以交替执行进程,还可以重叠执行进程(多CPU、多进程、同时执行)
-
信号量
用于进程间传递信号的一个整数值,在信号量可进行三种原子操作:初始化、递减、递增
进程的交互方式以及控制问题
-
进程间的资源竞争
互斥、死锁、饥饿
-
进程间通过共享合作
互斥、死锁、饥饿、数据一致性
-
进程间通过通信合作
死锁、饥饿
解决互斥问题
-
软件方法
由并发执行的进程担负解决问题的责任
-
硬件方法
中断禁用
专用机器指令
-
操作系统或程序设计语言中提供某种级别的支持
信号量
管程
消息传递
信号量
基本原理
两个或多个进程通过简单的信号进行合作,一个进程被迫在某一位置停止,直到它接收到一个特定的信号
两个原语
- semSignal(s):通过信号量s传送信号进程执行的原语,V操作
- semWait(s):通过信号量s接收信号进程执行的原语,P操作
用于互斥时,位于同一进程内;用于同步时,交错出现于两个合作进程内
互斥
信号量可以初始化成非负数
semWait操作使信号量减1。若值为负数,则执行semWait的进程阻塞,否则继续执行
semSignal操作使信号量加1。若值小于或等于0,则被semWait操作阻塞的进程被解除阻塞
同步
信号量一般初始化为1
S.count >= 0:可以执行semWait(s)而不被阻塞的进程数
S.count < 0: 阻塞在s.queue中的进程数
强信号量与弱信号量
强信号量:从阻塞队列移除进程的采用策略是先进先出
否则为弱信号量
管程
概述
管程是一个或多个过程、一个初始化序列和局部数据组成的软件模块
- 局部数据变量只能被管程的过程访问,任何外部过程都不能访问
- 一个进程通过调用管程的一个过程进入管程
- 在任何时候,只能有一个进程在管程中执行,调用管程的任何其他进程都被阻塞,以等待管程可用
互斥
管程中的数据变量每次只能被一个进程访问。可以把一共享数据结构放在管程中,从而提供对它的保护
同步
管程通过条件变量提供对同步的支持。条件变量只有在管程中才能被访问
消息传递
概述
合作进程之间进行信息交换
原语
- send (destination, message)
- receive (source, message)
同步
-
阻塞send,阻塞receive
发送者和接收者都被阻塞,直到完成信息的投递
-
无阻塞send,阻塞receive
接收者阻塞,直到请求的信息到达
-
无阻塞send,无阻塞receive
不要求任何一方等待
寻址
-
直接寻址
send原语包含目标进程的标识号;receive原语可显式地指定源进程,也可不指定
-
间接寻址
发送者将消息发送到合适的信箱;接收者从信箱中获得消息
消息排队原则
- 先进先出
- 优先级
六 并发:死锁和饥饿
死锁原理
- 一组相互竞争系统资源或进行通信的进程间的永久阻塞
- 没有一种有效的通用解决方案
- 都涉及两个或多个进程之间对资源需求的冲突
资源
-
可重用资源
一次只能供一个进程安全地使用,并且不会由于使用而耗尽的资源
如处理器、I/O通道、内存、外存、设备、文件、数据库、信号量
-
可消耗资源
可以被创建和销毁的资源
如中断、信号、消息、I/O缓冲区中的信息
资源分配图
圆形表示进程,方形表示资源,方形的圆点表示资源的一个实例
线的箭头指向资源表示进程请求资源,线的箭头指向进程表示进程占有资源
死锁的条件
-
互斥
一次只有一个进程可以使用一个资源
-
占有且等待
当一个进程等待其他进程时,继续占有已经分配的资源
-
不可抢占
不能强行抢占进程已占有的资源
-
循环等待
存在一个封闭的进程链,使得每个进程至少占有此链中下一个进程所需要的一个资源
处理死锁的方法
- 死锁预防
- 死锁避免
- 死锁检测与恢复
死锁预防
-
间接的死锁预防方法
预防前三个条件
互斥:该条件不可能被禁止
占有且等待:可要求进程一次性地请求所有需要的资源,并且阻塞进程直到所有请求都同时满足
不可抢占:如果占有某些资源的进程进一步申请资源时被拒绝,则该进程必须释放它最初占有的资源;如果进程A请求当前被进程B占有的一个资源,则操作系统可以抢占进程B,要求它释放资源
-
直接的死锁预防方法
预防第四个条件
循环等待:定义资源类型的线性顺序。如果一个进程已经分配到了R类型的资源,那么它接下来请求的资源只能是那些排在R类型之后的资源类型
死锁避免
-
如果一个进程的请求会导致死锁,则不启动此进程
进程启动拒绝
对于某种资源,只有所有当前进程的最大请求量加上新的进程请求可以满足时,才会启动新进程
-
如果一个进程增加的资源请求会导致死锁,则不允许此分配
资源分配拒绝
动态的检测资源分配状态以确保循环等待条件不可能成立
资源分配拒绝(银行家算法)
安全状态
若存在一个安全序列,则系统处于安全状态
安全、不安全和死锁状态空间
- 安全状态不是死锁状态
- 死锁状态是不安全状态
- 不是所有不安全状态都是死锁状态
数据结构
系统有n个进程和m种不同类型的资源
Available:Available[j]=k:资源类型Rj现有k个实例
Claim: Claim[i,j]=k:进程Pi最多可申请k个Rj的实例
Allocation:Allocation[i,j]=k:进程Pi现在已经分配了k个Rj的实例
Need:Need[i,j]=k:进程Pi还可能申请k个Rj的实例
Need[i,j] = Claim[i,j] - Allocation[i,j]
安全性算法
用于确定计算机系统是否处于安全状态
步骤:
- 设Work和Finish分别是长度为m和n的向量,初始化Work:=Available,Finish[i]=false(i=1,2,…,n)
- 查找 i 使其满足 a. Finish[i] = false b. Needi <=Work 若没有这样的 i 存在,转到4
- Work := Work + Allocationi Finish[i] := true 返回到2
- 如果对所有 i,Finish[i] = true,则系统处于安全状态
资源请求算法
设Requesti 为进程Pi的请求向量
-
如果Requesti <= Needi ,那么转到第2步。否则,产生出错条件,因为进程已超过了其请求
-
如果Requesti <=Available,那么转到第3步。否则,Pi等待,因为没有可用资源
-
假定系统可以分配给进程Pi 所请求的资源,并按如下方式 修改状态:
Available:= Available – Requesti
Allocationi := Allocationi + Requesti
Needi := Needi – Requesti
-
调用安全性算法确定新状态是否安全
安全—操作完成且进程Pi分配到其所需要的资源
不安全—进程Pi必须等待,并将数据结构恢复到原状态(即3的逆操作)
死锁检测
概述
- 死锁检测策略不限制资源访问或约束进程行为
- 系统周期性地执行检测算法,检测循环等待条件是否成立
死锁检测算法
检测时机
- 每个资源请求发生时
- 隔一段时间
步骤
新定义一个请求矩阵Q
- 标记Allocaiton矩阵中一行全为零的进程
- 初始化一个临时向量W,令W等于Available向量
- 查找下标i,使进程i当前未标记且Q的第i行小于等于W,如果找不到这样的行,终止算法
- 如果找到这样的行,标记进程i,并把Allocation矩阵中的相应行加到W中,返回步骤3.
若最后有未标记的进程时,存在死锁,每个未标记的进程都是死锁的
恢复死锁
- 取消所有死锁进程
- 把每个死锁进程回滚到某些检查点,并重新启动所有进程
- 连续取消死锁进程直到不再存在死锁。选择取消进程的顺序基于某种最小代价原则。每次取消后,必须重新调用检测算法,以测试是否仍存在死锁
- 连续抢占资源直到不再存在死锁。同3