第2章 处理器管理
处理器管理是OS的重要组成部分,负责管理、调度和分配计算机中最重要的资源——处理器
处理器管理是OS的最核心的部分
2.1 处理器和寄存器
寄存器
- 用户可见寄存器
- 数据寄存器(通用寄存器)
- 地址寄存器(索引、栈地址、段地址等)
- 页表基址寄存器:只有一个,哪个进程在运行,存的就是哪个
- 控制与状态寄存器
- 控制寄存器
- 程序计数器PC
- 指令寄存器IR
- 条件码CC
- 标志位(中断位、中断允许位、中断屏蔽位、处理器模式位、内存保护位...)
- 程序状态字PSW 指记录当前程序运行的动态信息,通常包含:
- 程序计数器,指令寄存器,条件码
- 中断字,中断允许/禁止,中断屏蔽,处理器模式,内存保护、调试控制
- 可以设置一组控制与状态寄存器、也可专设一个PSW寄存器
- 例如,x86中,PSW由标志寄存器EFLAGS和指令指针寄存器EIP组成
2.2 指令与处理器模式
指令执行过程
- 取指:CPU根据PC取指令,放入IR
- 解码:对指令译码
- 执行:发出各种控制命令,执行微操作系列,PC++
特权指令与非特权指令
- 特权指令:仅在内核态下才能使用的指令,设计改变机器状态、修改寄存器内容、启动设备IO等
- 如启动IO设备、设置时钟、清空内存、建立存储键、设置中断屏蔽位、修改寄存器值、加载PSW等
- 非特权指令
- 能被所有程序使用
原因:应用程序在执行有关资源管理的机器指令时易于导致系统混乱,造成系统或用户信息被破坏
内核态和用户态
- 计算机一般设置0、1、2、3等四种运行模式, 建议分别对应:0操作系统内核、1系统调用、 2共享库程序、3用户程序等保护级别
- 0模式可以执行全部指令;3模式只能执行非特权指令;其他每种运行模式可以规定执行的指令子集
- 一般现在0对应内核态(管态),3对应用户态(目态)
状态转换
下列情况发生用户态→内核态
- 程序请求执行系统调用
- 程序运行时产生中断事件(如IO操作完成),转向中断处理程序
- 程序运行时发生异常,转向异常处理程序
中断和异常是用户态转型内核态的仅有途径
OS内核处理完成后,调用中断返回指令(如 Intel的iret)触发:内核模式→用户模式
2.3 中断
概念
- 指程序执行过程中,遇到继续处理的事情,暂时中止(而非终止)CPU上现行程序的执行(并保护现场),转去执行事件处理程序
- 操作系统是中断驱动的
- 中断是激活操作系统的唯一方式
- 激活内核的情况
- 时间片未到,中断(IO、异常...)
- 时间片到,中断(时钟中断)
- 进程执行完return
中断、异常与系统异常
- (狭义)中断/异步中断:处理器之外的中断事件——又称外中断
- 可屏蔽、不可屏蔽
- IO中断、时钟中断、外部信号中断
- 异常:当前运行指令引起的中断,处理器内部的中断信号——内中断
- 地址异常(超出范围)、算术异常、处理器硬件故障...
- 系统异常:执行陷入指令而触发系统调用
- 请求设备、请求IO、创建进程等
2.4 中断源
- 处理器硬件故障(处理器、内存储器、总线等硬件故障)
- 处理原则:保护现场、停止设备、停止CPU、等待人工干预
- 程序性中断(处理器执行机器指令引起)
- 算术异常:简单报告用户、或者由用户编写中断元程序处理
- 非法指令、用户态使用特权指令、地址越界、非法存取等指令异常:终止进程
- 终止进程指令:终止进程
- 虚拟地址异常:调整内存后重新执行指令
- 自愿性中断事件(执行陷入指令请求OS服务引起;在操作系统中,它一般又被称作系统调用)
- 陷入OS,保护现场,根据功能号查入口地址,跳转具体处理程序
- IO中断事件
- I/O完成:调整进程状态,释放等待进程
- I/O出错:等待人工干预
- I/O异常:等待人工干预
- 外部中断事件
- 时钟中断、间隔时钟中断:记时与时间片处理
- 设备报到与结束中断:调整设备表
- 键盘/鼠标信号中断:根据信号作出相应反应
- 关机/重启动中断:写回文件,停止设备与 CPU
2.5&2.6 中断系统
- 中断系统需要软、硬件配合
- 中断响应——硬件子系统完成
- 中断处理——软件子系统完成
- 中断装置——发现并响应中断/异常的硬件装置
- 处理器外的中断:中断控制器(IRQ)
- 处理器内的中断:指令控制逻辑和实现路线,也称陷阱
- 请求OS服务的系统异常:系统陷阱
- 中断处理:
- 发现中断源
- 保护现场
- 转向中断/异常处理程序
- 恢复现场
2.7 多中断的响应和处理
- 中断屏蔽
- 当计算机检测到中断时, 中断装置通过中断屏蔽位决定是否响应已发生的中断
- 中断优先级
- 当计算机同时检测到多个中断时
- 硬件方法:根据排定的优先级顺序做一个硬件链式排队器,产生高一级的中断事件时,屏蔽优先级比他低的中断源
- 软件方法:编写一个查询程序,根据优先级高低进行查询,发现中断请求就转入中断处理
- 当计算机同时检测到多个中断时
- 嵌套处理
- 允许运行某些中断处理程序时仍能够响应中断
- 必须预先规定优先级,运行高优先级的中断打断低优先级的中断处理程序
- 规定嵌套最大层数,一般不超过3
- 中断的嵌套处理改变中断处理次序,先响应的有可能后处理
多中断
- 决定中断处理次序的因素
- 中断屏蔽可以使中断装置不响应某些中断
- 中断优先级决定了中断装置响应中断的次序
- 中断可以嵌套处理, 但嵌套的层数应有限制
- 中断的嵌套处理改变了中断处理的次序
2.8 进程及其状态*
进程的定义
- 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动
- 进程是操作系统进行资源分配和调度的一个独立单位
- 进程的五个实体部分(P,C,D,R,PSW)
- (OS管理运行程序的)数据结构P
- (运行程序的)内存代码C
- (运行程序的)内存数据D
- (运行程序的)通用寄存器信息R
- (OS控制程序执行的)程序状态字信息PSW
不同程序在不同数据集上:两个无关进程
不同程序在同一个数据集上:共享数据的交往进程
相同代码在不同数据集上:共享代码的无关进程
- 共享的代码成为可再入程序,如编译程序
- 可再入程序是纯代码的
相同程序,数据集合不同,算不同进程
多次运行,算多个进程
进程状态*
- 运行态:占有CPU运行
- 就绪态:具备一切运行条件,等待CPU
- 阻塞/等待态:等待资源,除了CPU还缺别的
三态模型*
- 等待资源、IO、信号
- 资源满足、IO结束、信号完成
- 处理器空闲、高优先级抢占
- 运行时间片到、有更高优先级进程
五态模型*
增加了进程挂起
- 运行资源不足表现为:性能低、死锁
- 解决:剥夺某些进程的内存及其他资源, 调入OS管理的对换区,不参加进程调度,待适当时候再调入内存、恢复资源、参与运行
- 挂起态与等待态有着本质区别,后者占有已申请到的资源处于等待,前者没有任何资源
七态模型*
2.9 进程的数据描述
进程控制块
PCB Process Control Block
系统在创建进程时候建立PCB,进程运行结束才回收,进程借助PCB才能被调度执行
- 标识信息:唯一标识进程的信息
- 系统分配的、用户定义的标识号、进程组标识号
- 现场信息:用于存放该进程运行时的处理器现场信息
- 控制信息:用于存放与管理、调度进程相关的信息
进程映像
Process Image
某一时刻进程的内容及其执行状态集合:
- 进程控制块: 保存进程的标识信息、状态信息和控制信息
- 进程程序块: 进程执行的程序空间
- 进程数据块: 进程处理的数据空间,包括数据、处理函数的用户栈和可修改的程序
- 核心栈: 每个进程绑一个,进程在内核态工作时用,保存中断/异常现场,也用于传参、返回地址等。
- 进程在内核模式下运行时使用的堆栈,中断或系统过程使用进程映像是内存级的物理实体,又称为进程的内存映像
进程上下文
Process Context
进程上下文刻画了进程的执行情况
-
用户级上下文:用户程序块/用户数据区/ 用户栈/用户共享内存
-
寄存器上下文:PSW/栈指针/通用寄存器
-
系统级上下文:PCB/内存区表/核心栈
2.10 进程的管理
对进程的管理和控制使用原语
进程控制与管理
- 进程创建:进程表.push(new PCB)
- 进程撤销:回收PCB,修改进程表
- 进程阻塞:修改PCB,移入等待队列
- 进程唤醒:修改PCB,移入就绪队列
- 进程挂起:修改状态并出入相关队列,收回内存等资源送至对换区
- 进程激活:分配内存,修改状态并出入相关队列
2.11 进程切换与模式切换
进程切换
- 保存被中断进程的上下文
- 转向进程调度
- 恢复待运行进程的上下文
过程:详见PPT
模式切换
- 用户模式到内核模式
- 由中断/异常/系统调用中断用户进程 执行而触发
- 处理器模式转为内核模式
- 保存当前进程的PC/PSW值到核心栈
- 转向中断/异常/系统调用处理程序
- 由中断/异常/系统调用中断用户进程 执行而触发
- 内核模式到用户模式
- OS执行中断返回指令将控制权交还 用户进程而触发
- 从待运行进程核心栈中弹出PSW/PC值
- 处理器模式转为用户模式
- OS执行中断返回指令将控制权交还 用户进程而触发
2.12 多线程技术概述
单线程
传统进程是单线程结构
存在问题
- 进程切换开销大
- 进程通信开销大
- 限制了进程并发效率
- 降低并行计算效率
解决思路
- 进程的两项功能:
- 独立分配资源
- 仍有进程完成,作为系统资源分配和保护的基本单位
- 被调度分派执行
- 交给称作“线程”的实体来完成
- “线程”作为系统调度和分派的基本单位
- 独立分配资源
多线程
多线程环境下的进程:
- 操作系统中进行保护和资源分配的独立单位,具有:
- 用来容纳进程映像的虚拟地址空间
- 对进程、文件和设备的存取保护机制
多线程环境下的线程:
- 线程是进程中能够并发执行的实体,是进程的组成部分
- 线程是进程的一条执行路径,是调度的基本单位
多线程环境下线程的状态和调度:
- 运行、就绪、睡眠,无挂起
- OS感知线程:
- 处理器调度的对象是线程
- 进程没有三状态,只有挂起
- OS不感知线程:
- 处理器调度进程
- 用户空间中的用户调度程序调度线程
2.13&2.14 KLT和ULT
内核级线程
KLT, Kernel-Level Threads
-
OS提供了一个应用 程序设计接口API, 供开发者使用KLT
-
OS直接调度KLT
-
优点:
- 进程中的一个线程被阻塞了,内核能调度同一进程的其它线程占有处理器运行
- 多处理器环境中,内核能同时调度同一进程中多个线程并行执行
- 内核级线程数据结构和堆栈小,切换快
- 内核自身也可用多线程技术实现,能提高操作系统的执行速度和效率
-
缺点
- 应用程序线程在用户态运行,线程调度和管理在内核实现,在同一进程中,控制权从一个线程传送到另一个线程时需要“用户态—内核态—用户态”切换,系统开销较大
用户级线程
ULT, User-Level Threads
-
线程管理的所有工作都由应用程序完成,内核没有意识到线程的存在
-
优点:
- 线程切换不需要内核模式,能节省模式切换开销和内核的宝贵资源
- 进程自定义调度算法
- 能运行在任何OS上,内核在支持ULT方面不需要做任何工作
-
缺点:
- 不能利用多处理器的优点,OS调度进程,仅有一个ULT能执行
- 一个ULT的阻塞,将引起整个进程的阻塞
jacketing技术
- 把阻塞式系统调用改造成非阻塞式的
- 当线程陷入系统调用时,执行jacketing 程序
- 由jacketing 程序来检查资源使用情况,以决定是否执行进程切换或传递控制权给另一个线程
混合式线程
- 用户层线程在用户线程库中实现
- 内核层线程在OS内核中实现
- 内核必须支持内核级多线程的建立、管理和调度,也允许应用程序建立、管理和调度用户级线程
- 程序员可以针对特定应用和机器调节内核级线程的数目,以达到整体最佳结果
- 单应用的多个 ULT可以映射成 一些KLT,通过调整KLT数目, 可以达到较好的 并行效果
2.15 处理器调度的层次
- 高级调度,又称作业调度、长程调度
- 挑选作业进入内存,并为其分配所需资源并创建作业对应的用户进程
- 控制多道程序的道数
- 中级调度,又称平衡负载调度
- 决定主存中的可用进程集合
- 内存紧缺时将不能运行的进程换出内存,"挂起"
- 内存富裕时,重新调回内存
- 低级调度,又称进程调度、短程调度
- 决定哪个可用进程占用处理器执行
2.16&2.17 处理器调度算法
指标
- 资源利用率
- 响应时间
- 周转时间(提交给系统到运行完成)
- 吞吐量
- 公平性
调度算法
- FCFS 先到先服务 非抢占式
- RR 时间片轮转 抢占式
- 抢占时间:时间片用完
- SPN 最短进程优先 非抢占式
- 抢占时间:进程到来/结束时,需要预估时间
- SRT 最短剩余时间优先 抢占式
- 抢占时间:进程到来/结束时,需要预估时间
- HRRN 最高相应比优先 非抢占式
- highest response ratio next
- feedback 多级反馈队列 抢占式
- Q:如何照顾低优先级队列?
- A:给长一点时间
补充内容
FCFS
-
非抢占式
-
根据到达时间
-
一个短进程可能不得不等待很长时间才能获得执行
-
偏袒计算为主的进程
- I/O多的进程不得不等待计算为主的进程做完
RR
- 抢占式
SPN
- 非抢占式
- 选择所需处理时间最短的进程
- 短进程将会越过长进程,优先获得调度
- 偏袒短进程,只要持续不断地提供更短的进程,长进程就有可能饿死
SRT
- 抢占式
- 调度器总是选择预期剩余时间更短的进程
- 当一个新进程加入就绪队列,他可能比当前运行的进程 具有更短的剩余时间,只要该新进就绪,调度器就可能 抢占当前正在运行的进程
HRRF
- 非抢占式
Feedback
- 建立多个不同优先级的就绪进程队列
- 多个就绪进程队列之间按照优先数调度
- 当一个进程第一次进入系统时,它被放置在RQ0,当它第一次被抢占后并返回就绪状态时,它被放置在RQ1。在随后的时间里,每当它被抢占时,它被降级到下一个低优先级队列中。
抢占的决策可能是在一个进程到达时,或者在一个中断发生后把一个被阻塞的进程置为就绪态时,或者基于周期性的时间中断
- 改进:
- 优先级越高,时间片越短
- 一段时间后给低优先级的进程提升优先级
关于fork
父进程和子进程可以并发执行;
int main(){
fork();
fork();
fork();
}