进程
进程基本上就是执行中的程序,进程内部的执行必须有顺序性.
进程被定义成一个表示系统中需要实现的基本工作单元的实体
简单地说,当执行被写成文本文件的计算机程序时,它就变成一个执行程序中的指令的进程.
当程序被加载进内存成为进程时,可以被划分成四个部分-- 栈,堆,文本区和数据区. 下面这幅图片简单地显示了进程在主存中的布局.
组件 | 描述 |
---|---|
栈 | 栈保留了例如方法/函数指针等临时数据,返回地址和局部变量 |
堆 | 用于运行时动态分配内存 |
文本 | 包含保存在PC(程序计数器)的当前的行为和处理器寄存器的内容 |
数据 | 包括静态和全局变量 |
程序
程序是一段代码块,它可以是单行,也可以上万行代码.计算机程序通常由程序员用编程语言编写.例如下面的C语言示例程序
#include<stdio.h>
int main() {
printf("Hello, World!
");
return 0;
}
计算机程序是指令的集合,从而在被计算机执行时可以完成特定的任务. 如果将它与进程进行比较,可以说进程是程序的动态实体.
计算机程序的一部分执行确切定义的任务--算法, 计算机程序,库和相关联的数据被称作软件.
进程生命周期
当一个进程被执行,会经过不同的状态. 这些阶段在不同的操作系统中可能不同,并且状态的名字也没有标准化.
总的来说,进程的状态会是以下五种中的一个
状态 | 描述 |
---|---|
开始 | 当一个进程被创建时的初始状态 |
就绪 | 进程等待被分配处理器. 此时进程已经获得它所需要的资源,等待操作系统分配处理器运行,可以从开始/等待状态转换(分配资源),也可以从运行状态转换(被操作系统中断,剥夺CPU) |
运行 | 一旦OS调度器把处理器分配给进程,进程的状态就变成运行,并且处理器开始执行它的指令 |
等待 | 当进程等待某些资源,如用户输入或文件解锁,就会进入等待状态 |
退出 | 进程完成了它的执行或被操作系统终止,就变成退出状态并等待从主存中移出 |
PCB(Process Control Block) 进程控制块
进程控制块是操作系统为每个进程维护一个的数据结构. 它通过整型的进程id(PID)来唯一标识进程. PCB保留了操作系统需要的信息
信息 | 描述 |
---|---|
状态 | 当前进程的状态(上面描述的生命周期里的) |
进程权限 | 当允许/不允许访问系统资源时需要 |
PID | 操作系统中进程的唯一标识符 |
指针 | 指向父进程 |
PC | 程序计数器,指向进程要执行的下一条命令的地址 |
CPU寄存器 | 进程在运行状态时需要存储多种寄存器 |
CPU调度信息 | 进程的优先级和其他调度所需要的信息 |
内存管理信息 | 取决于操作系统的内存可包含页表,内存上限,段表 |
累积信息 | CPU所运行的周期,时间限制和运行ID等等 |
IO状态 | 包括了分配给进程的一系列I/O设备 |
PCB的架构完全依赖于操作系统,不同的操作系统可能有不同的信息,这是一张PCB的简化表
PCB被进程维护,与进程一同被创建,进程销毁也会被销毁.
进程调度
进程调度就是用一个特定的策略来将当前运行的进程移出,并选择合适的进程分配CPU的活动.
进程调度是多道操作系统的重要部分. 这样的操作系统允许多个进程同时加载进内存,并且让载入的程序对CPU进行时分复用.
进程调度队列
OS将所有PCBs维护在队列中,不同状态的进程有不同的队列. 当进程的状态发生改变,他的PCB从当前队列中删除并连接到新状态对应的队列上.
操作系统维护下面这些重要的进程调度队列
- 工作队列 保存系统中的所有进程
- 就绪队列 维护内存中的进程集合,就绪并且等待执行,新创建的进程总是会加入到这个队列.
- 设备队列 由于I/O设备的不可用性导致阻塞的进程构成的队列
OS可以用不同的策略来管理每个队列(FIFO,RoundRobin,优先级等). OS调度器决定了就绪和运行队列的进程怎样进行移动,并保证每个处理器核心只能有一个进程实体; 在上图中,调度器被包含在了CPU中.
二元进程模型
二元进程模型用来表示进程的状态是运行中还是不在运行中
状态 | 描述 |
---|---|
运行中 | 当新的进程被创建,它作为运行中状态进入系统 |
非运行中 | 当前不在运行的进程被保存在这个队列,等待执行. 这个队列的每个实体都是一个进程的指针. 用链表来实现. 调度器按照如下准则运作: 当进程中断,把它转移到等待队列,如果进程已经完成或退出, 将这个进程丢弃. 对于所有情况,调度器都会在队列中选一个新的进程执行 |
调度器
调度器是用不同方式处理进程调度的系统软件,它的主要任务是选择提交到系统的工作和决定执行哪个进程. 有三种类型
- 高级调度
- 低级调度
- 中级调度
高级调度
也叫作工作调度. 高级调度决定允许哪个程序进入系统来处理. 它从队列中选择进程并把进程加载到内存来执行. 加载到内存后的进程才能被CPU调度.
工作调度的主要目标是保证不同类型工作的平衡, 如I/O密集型和处理器密集型. 它也控制了多道处理的度. 如果当前多道度是稳定的,那么平均进程创建率应与平均进程离开率持平.
在某些系统中, 高级调度可以不保证可靠性或最小化. 分时操作系统没有高级调度. 进程的状态从创建到就绪的转换就需要高级调度.
低级调度
也叫作CPU调度. 它的目的是提升系统的性能来符合设定的标准. 它负责将进程的状态从就绪转化到运行, CPU调度从就绪队列中选择一个进程来分配CPU.
中级调度
中级调度是交换的一部分. 它将内存的进程移出,从而减少多道程序度,并且负责管理这些移出的进程.
一个运行的进程可能因为发起I/O请求而挂起,挂起的进程无法继续推进,在这种情况下为了从内存中移出进程,为其他进程腾出空间,挂起的进程被移动到外存上. 这个过程叫做对换,进程被叫做换出和换入. 对换对于提升进程多样性非常重要.
调度的对比
编号 | 高级调度 | 低级调度 | 中级调度 |
---|---|---|---|
1 | 工作级别的调度 | CPU级别的调度 | 进程交换 |
2 | 速度最慢 | 速度最快 | 高级和低级之间 |
3 | 控制多道程序度 | 对多道程序度的控制较小 | 降低多道程序度 |
4 | 在分时系统中几乎不需要 | 分时系统中也很小 | 分时系统的一部分 |
5 | 从池中选择进程载入内存来执行 | 选择准备执行的进程 | 重新将进程载入内存从而继续被执行 |
上下文切换
上下文切换是一种将CPU的状态或上下文存储到PCB上,或从PCB读取的机制,从而保证进程的执行还原到之前的状态. 上下文切换器用这种技术使单CPU能被多个进程分享,上下文切换是多任务操作系统特性的重要部分.
当调度器把CPU从当前进程的执行切换到另外一个进程,当前运行的进程的状态被存到PCB中. 之后从下一个运行进程的PCB中载入状态并赋值给PC,寄存器等. 之后,第二个进程得以开始执行.
上下文切换是计算密集的, 因为寄存器和内存状态被写入和读入. 为了避免庞大的上下文切换时间, 一些硬件系统提供两到多组处理器寄存器. 当进程切换发生时,下面的信息会被存储.
- PC
- 调度信息
- 基寄存器和界寄存器的值
- 当前用到的寄存器
- 改变的状态
- I/O状态信息
- 累积信息
操作系统调度算法
进程调度器基于特定的调度算法为不同的进程分配CPU.在本章节中我们会讨论六个著名的调度算法.
- 先来先服务(FCFS)调度
- 短作业优先(SJN)调度
- 优先级调度
- 最短存留时间
- 时间片轮转调度(RR)
- 多级队列调度
这些算法既有不可抢占的也有可抢占的. 不可抢占算法是指一旦进程进入了运行状态,它就不能被剥夺CPU资源,直到完成它被分配的CPU时间. 抢占算法是基于优先级的, 当一个高优先级的进程进入就绪态时调度器可能会剥夺一个正在运行的低优先级进程的CPU.
先来先服务(FCFS)
- 工作是基于先来先服务原则执行的
- 不可抢占, 先发制人的调度算法
- 很容易理解和实现
- 基于先进先出的队列实现
- 由于平均等待时间很长导致性能差劲
每个进程的等待时间如下-
进程 | 等待时间:服务开始时间-到达时间 |
---|---|
P0 | 0-0=0 |
P1 | 5-1-4 |
P2 | 8-2=6 |
P3 | 16-3=13 |
平均等待时间: (0+4+6+13)/4 = 5.75
短作业优先(Shortest Job Next)
- SJF(Shortest Job First) 更常见
- 不可抢占, 先发制人的调度算法
- 最小化等待时间的最好方案
- 在所需CPU时间已知的批处理系统中非常容易实现
- 在所需CPU时间未知的交互式系统中无法实现
- 处理器需要预先直到进程需要多少时间
给出:进程表及它们的到达时间和执行时间
每个进程的等待时间如下-
|进程|等待时间|
|P0|0-0=0|
|P1|5-1=4|
|P2|14-2=12|
|P3|8-3=5|
平均等待时间: (0+4+12+5)/4 = 21/4 = 5.25
优先级调度
- 优先级调度是一种非抢占算法, 且是在批处理操作系统中最为常见的调度算法
- 每个进程都有优先级, 拥有最高优先级的进程被最先执行
- 相同优先级的进程基于先来先服务执行
- 优先级可以通过内存需求,时间需求或任何资源需求来决定
给出:进程表及他们的到达时间,执行时间和优先级. 优先级数字越高优先级越大
进程 | 到达时间 | 执行时间 | 优先级 | 服务时间 |
---|---|---|---|---|
P0 | 0 | 5 | 1 | 0 |
P1 | 1 | 3 | 2 | 11 |
P2 | 2 | 8 | 1 | 14 |
P3 | 3 | 6 | 3 | 5 |
先执行P0, 结束时间为5, 此时P1,P2,P3 都已经到达, 执行顺序为P3,P1,P2
每个进程的执行时间如下-
进程 | 等待时间 |
---|---|
P0 | 0-0=0 |
P1 | 11-1=10 |
P2 | 14-2=12 |
P3 | 5-3=2 |
平均等待时间:(0+10+12+2)/4 = 24/4 = 6
最短存留时间
- 最短存留时间是SJF算法的可抢占版
- 处理器被分配给所剩执行时间最短的工作, 但可以被一个有更短完成时间的新就绪的工作抢占
- 在所需CPU时间未知的交互式系统中无法实现
- 通常用在短工作需要提升性能的批处理环境
时间片轮转调度
- RR是抢占算法
- 每个进程都被分配到一个固定的执行时间,量子
- 一旦进程执行完它被分配到的时间片, 它就会被抢占,由下一个进程执行它分配到的时间片
- 进程抢占时需要切换上下文
每个进程的等待时间如下-
进程 | 等待时间 |
---|---|
P0 | (0-0)+(12-3)=9 |
P1 | (3-1)=2 |
P2 | (6-2)+(14-9)+(20-17)=12 |
P3 | (9-3)+(17-12)=11 |
平均等待时间:(9+2+12+11)/4=8.5
多级队列调度
多级队列调度不是一个独立的的调度算法, 它使用其他现存的算法来分组和调度具有相同特征的工作
- 多个队列中的单个队列维护具有相同特征的进程
- 每个队列有自己的调度算法
- 优先级是分配给每个队列的
比如, CPU密集型工作会被调度到一个队列中, 所有的I/O密集型会在另一个队列. 进程调度器交替的从每个队列中选择工作,并基于每个队列被分配到的算法分配CPU