一文详解操作系统进程管理

1. 什么是进程进程即正在运行的程序的一个实例 。
当启动一个程序,程序会从磁盘被读取到内存,CPU 再从内存中读取指令,对其解码,然后执行指令(比如两数相加,访问内存,检查条件,跳转函数等) 。完成这条指令后,CPU 继续重复上述操作 。这样子就可以实现一个 CPU 可以对一个进程,以一对一的形式进行指令读取与执行 。

一文详解操作系统进程管理

文章插图
 
我们把操作系统做某件事,抽象成一种概念,称之为一个任务 。一个进程可以对应一个任务,也可以对应多个任务 。
早期的计算机只有一个 CPU,多个任务需要运行怎么办?需要依次排队等待,串行执行,一个任务执行完毕,才能执行下一个 。这种方式存在着明显的弊端,假设排在前面的 A 任务需要执行5小时,而排后面的B任务仅需要1分钟,那么 B 任务必须等待 A 任务5小时完成后,才能执行,这种方式显得极其不灵活 。
后来就有了多任务系统,在CPU同一时间只能处理一个任务的前提下,每个任务有一定的执行时长,比如任务A执行0.001s,切换到任务B执行0.05s,再切换到任务C执行0.01s...不断循环 。这种机制也就可以在一定程度上解决上述任务B需要长时间等待的问题 。
一文详解操作系统进程管理

文章插图
 
由于 CPU 速度非常快,这种多个任务不断切换,会给用户一种任务并行执行的错觉,这种也被称为是伪并行调度 。既然有伪并行,那么也会有真并行 。在现代计算机中,常见的CPU核数可以达到8核甚至更多,操作系统可将每一个核视为一个CPU,那么8核CPU就可以真并行执行8个任务 。还有更进一步的,即一个计算机内,有多个CPU 。至于多个CPU与多核的区别,感兴趣的读者可以参考多核 CPU 和多个 CPU 有何区别? 。
那么我们继续基于伪并行进一步探讨 。伪并行虽然可以解决上述任务等待的问题,但是依然还存在一系列未解之谜:
- 每个任务应该执行多长时间?
- 如何找到要执行的下一个任务?
- 有些任务涉及了资源操作,执行到一半,切换任务,那么这些资源怎么办?
......
为了解决上面一系列谜题,我们需要一种模型对任务进行详尽的描述记录 。一个进程可以对应一个任务,也可以对应多个任务,当前还未涉及多线程,我们可以在此先把进程和任务当作是一对一的关系(这并不是为了理解而创造出来的一种暂时错误的假设) 。下面我们将进一步探讨关于进程更详细的内容,这些内容将有助于解释上面的问题 。
2. 进程模型2.1 PCB对于一个被执行的程序,操作系统会为该程序创建一个进程 。进程作为一种抽象概念,可将其视为一个容器,该容器聚集了相关资源,包括地址空间,线程,打开的文件,保护许可等 。而操作系统本身是一个程序,有一句经典的话 程序 = 算法 + 数据结构,因此对于单个进程,可以基于一种数据结构来表示它,这种数据结构称之为进程控制块(PCB),有一些教材也将其称为进程表 。不同的操作系统,PCB中包含的信息存在差异,大体上都会包含这些信息(该图来自《现代操作系统》) 。
一文详解操作系统进程管理

文章插图
 
2.2 进程状态那么什么原因会导致进程会被创建,从而生成PCB呢?常见的有以下几种
1. 系统初始化
2. 用户通过系统提供的API创建新进程
3. 批处理作业初始化 (什么是批处理作业)
4. 由现有进程派生子进程
一个进程,因为某种原因被创建了,那么它可以按照以下步骤进行一系列的初始化
1. 给新进程分配一个进程ID
2. 分配内存空间
3. 初始化PCB
4. 进入就绪队列
2.2.1 五状态模型
一文详解操作系统进程管理

文章插图
 
如图,进入就绪队列,其状态就会变为就绪态 。各个状态之间的关系描述如下:
就绪 -> 运行:当操作系统内存在着调度程序,当需要运行一个新进程时,调度程序选择一个就绪态的进程,让其进入运行态 。
运行 -> 就绪:运行态的进程,会占有CPU(参照一开始的饼状图) 。每个进程会被分配一定的执行时间,当时间结束后,重新回到就绪态 。
运行 -> 阻塞:进程请求调用系统的某些服务,但是操作系统没法立即给它(比如这种服务可能要耗时初始化,比如I/O资源需要等待),那么它就会进入阻塞态 。


推荐阅读