操作系统学习笔记-1:基础概念中,我们介绍了与操作系统相关的一些概念,在 操作系统学习笔记-2:体系结构设计和运行机制中,我们又介绍了操作系统的结构设计和运行机制,从这篇笔记开始,我们会逐一讲解操作系统的各个基本功能。

一切围绕这张图来进行:

1. 关于进程

1.1 进程:

为了方便操作系统管理,对并发执行的各个程序加以控制和描述,引入了进程的概念。

1.2 PCB:

定义:

之前的单道批处理系统,程序是串行执行的,内存中可能只需要记录单一程序的程度段和数据段即可;但是现在使用的是多道批处理系统,多个程序并发执行,内存中就可能存在多个程序自己的程序段和数据段,那么这时候就需要一个管理单元对这些东西加以区分、描述和管理,所以就额外多了一个进程控制块,也就是 PCB(process control block)。

系统会为每一个运行的程序分配 PCB 这么一个数据结构,用以描述进程的各种信息。PCB 是进程存在的唯一标志,进程与 PCB 是一一对应的的。

PCB 记录了关于进程的信息,这些信息包括:

  • 进程标识符:外部内部各一个
  • 处理机状态:通用寄存器、指令计数器、程序状态字 PSW,用户栈指针
  • 进程调度信息:进程状态、进程优先级、其它的进程调度信息
  • 进程控制信息:程序和数据的地址、进程同步和通信机制、资源清单、链接指针

1.3 进程实体:

程序段(程序代码)、数据段(变量、常量等),PCB(相关的管理信息) 共同构成了进程实体(进程映像)。一般认为 进程实体 === 进程 === PCB

PS:下文提到的多个进程的组织方式,也可以说就是多个 PCB 的组织方式

1.4 进程与程序的对比:

  • 进程是动态的(程序的执行),程序是静态的(有序代码的集合)
  • 进程是暂时的,程序是永久的
  • 进程和程序的组成不同
  • 通过多次执行,一个程序可以对应多个进程;通过调用关系,一个进程可以包括多个程序

2. 进程的组成和组织

2.1 单个进程的组成

  • 进程描述信息:进程标识符PID(区分不同进程)用户标识符 UID(区分不同用户)
  • 进程控制和管理信息:进程当前状态、进程优先级
  • 资源分配清单:程序段指针、数据段指针、键鼠
  • 处理机相关信息:各种寄存器的值

2.2 多个进程的组织方式

链接方式:

按照进程状态将 PCB 分为多个队列,OS 持有指向各个队列的指针(执行指针、就绪队列指针、阻塞队列指针)

索引(线性)方式:

按照进程状态建立几张索引表,OS 持有指向各个索引表的指针(执行指针、就绪表指针、阻塞表指针)

3. 进程的特征

  • 动态性:进程是程序的一次执行过程,是动态地产生、变化和消亡的
  • 并发性:内存中有多个进程实体,各个进程可以并发执行
  • 独立性:进程是系统进行资源分配和调度的一个独立单位
  • 异步性:各个进程以独立的、不可预知的速度推进
  • 结构性:每个进程都有一个自己的 PCB,进程由程度段、数据段、PCB 构成

4. 进程的状态/生命周期

4.1 五种基本状态:

**① 创建态:**初始化 PCB,为进程分配系统资源

**② 就绪态:**PCB 修改相应内容并被送到就绪队列。万事俱备(运行需要的条件都有了),只欠东风(只等 CPU 调度自己)

③ 运行态: PCB 修改相应内容,出队(可能还会恢复进程运行环境)。该进程此时占有 CPU 使用权,在 CPU 上运行(对于单核处理器,一个时刻只会有一个进程)

**④ 阻塞态(等待态):**进程进行系统调用,或者等待事件发生时,进入阻塞态,PCB 修改相应内容并被送到相应事件的阻塞队列

**⑤ 终止态(结束态):**回收为进程分配的资源,撤销 PCB

PS:由于事件有多个,所以阻塞队列一般也是有多个的,一个事件对应一个阻塞队列。而就绪队列就只有一个了。

4.2 进程状态的转换:

4.3 引入挂起操作后

(1)挂起:

前面所说的状态转换,是建立在内存资源够用的情况下 —— 当系统资源尤其是内存资源不够时,就需要将一些进程挂起(suspend),对换到外存中。

(2)原因:

引起进程挂起的原因是多样的,主要有:

  • 系统中的进程均处于阻塞态,处理器空闲,此时需要把一些阻塞进程对换出去,以腾出足够的内存装入就绪进程运行。

  • 进程竞争资源,导致系统资源不足,负荷过重,此时需要挂起部分进程以调整系统负荷,保证系统的实时性或让系统正常运行。

  • 把一些定期执行的进程(如审计程序、监控程序、记账程序)对换出去,以减轻系统负荷

  • 用户要求挂起自己的进程,以便根据中间执行情况和中间结果进行某些调试、检查和改正。

  • 父进程要求挂起自己的后代进程,以进行某些检查和改正。

  • 操作系统需要挂起某些进程,检查运行中资源使用情况,以改善系统性能;或当系统出现故障或某些功能受到破坏时,需要挂起某些进程以排除故障。

(3)状态转换

引入挂起操作后,在原来五种状态的基础上多了两个状态:就绪态变成了活动就绪态,且多了一个“静止就绪态/挂起就绪态“;原来的阻塞态变成了活动阻塞态,且多了一个“静止阻塞态/挂起阻塞态“。

状态解释
活动就绪态 → 静止就绪态操作系统根据当前资源状况和性能要求,可能会把活动就绪态对换出去,成为静止就绪态。处于静止就绪态的进程不再被调度执行
静止就绪态 → 活动就绪态内存中没有进程处于活动就绪态,或者处于静止就绪态的进程具有更高的优先级,那么静止就绪态就会被对换回来,此时才可能被调度执行
活动阻塞态→ 静止阻塞态操作系统根据当前资源状况和性能要求,可能会把活动阻塞态对换出去,成为静止阻塞态。
静止阻塞态→ 静止就绪态常见的情况是,引起进程等待的事件发生之后,相应的静止阻塞态进程将转换为静止就绪态
静止阻塞态→ 活动阻塞态但有时候,如果静止阻塞态进程的优先级高于静止就绪队列中的任何进程、并且系统有把握它等待的事件即将完成,那么就会激活为活动阻塞态
运行态→ 静止就绪态优先级较高的静止阻塞态在等待的事件完成后,可能会抢占 CPU,若此时资源不够,则可能导致正在运行的进程挂起为静止就绪态
创建态→ 静止就绪态操作系统根据当前资源状况和性能要求,可能会在进程创建完就把它对换到外存

PS:进程一旦被挂起,就意味着它被对换到了外存中,此时该进程无法再被 CPU 直接调度,除非它被对换回内存中,回到活动就绪态。比如静止就绪态、静止阻塞态,最后要得到 CPU 的调度,都必须经历回归到活动就绪态的过程。

那么一个状态具体是如何切换到另一个状态的呢?

5. 进程的控制

在前面我们已经说过,进程的生命周期有多个状态,而状态的切换实质上是通过修改 PCB 的信息、让 PCB 出队或者入队来实现的,但是是谁来控制这个过程呢?—— 答案就是进程控制,进程控制指的是对系统中所有进程,从创建到终止的全过程实行的管理和控制。而进程控制是通过操作系统内核的 原语操作 来实现的。

操作系统内核一览,其中一个核心就是原语操作
原语(Primitive)其实就是程序 —— 由若干条机器指令构成,用以完成特定功能的一段程序。原语操作属于**原子操作**(Atomic operation),具有不可中断性,一旦执行就不允许被打断。这种原子操作是依靠关中断指令实现的,在关中断指令下,即使有中断信号发射过来,也不会调用中断处理程序去处理中断,这就保证了原语操作不会被打断。而在开中断指令下,才会去处理中断。

原语的基本操作无非三个:

  • 更新 PCB 中的信息(修改进程状态标志、保存当前运行环境到 PCB、从 PCB 中恢复运行环境)
  • 将 PCB 插入到合适的队列
  • 分配/回收资源

创建原语和撤销原语配对,阻塞原语和唤醒原语配对,所以这里我们放在一起讲。

(1)创建原语

创建原语负责创建进程,具体包括:申请空白的 PCB,为新进程分配所需资源、初始化 PCB、将 PCB 插入到就绪队列。

引起进程创建的事件一般有四种:

  • 用户登录:分时系统中,用户登录成功,系统会为其建立一个新的进程
  • 作业调度:多道批处理系统中,从作业队列取出作业放入内存时,会为其建立一个新的进程
  • 提供服务:用户向操作系统请求服务时,会创建一个进程来处理请求
  • 应用请求:应用/用户进程主动请求创建一个子进程

(2)撤销原语

撤销进程负责终止进程,具体包括:从 PCB 集合中找到终止进程的 PCB,如果进程正在运行,则立即将它的 CPU 使用权移交给其它进程。接着终止它的所有子进程,将该进程的资源还给父进程或者操作系统,最后再删除 PCB。

引起进程终止的事件一般有三类:

  • 正常结束
  • 异常结束
  • 外界干预

(3)阻塞原语

阻塞原语负责让进程从运行态转换到阻塞态,具体包括:找到要阻塞的进程的 PCB,保存当前运行环境到 PCB(方便后续恢复),修改 PCB 状态信息。接着暂停进程的运行,将 PCB 插入相应事件的等待队列

引起进程阻塞的事件一般是:

  • 等待系统分配资源
  • 请求系统某些服务(比如打印服务)
  • 启动某种操作(比如 I/O 操作)
  • 新数据尚未到达
  • 无新工作可做

注意:前面我们说过,进程从运行态切换到阻塞态,是一个主动的过程,这个主动体现在是进程自己调用了阻塞原语

(4)唤醒原语

唤醒原语负责让阻塞的进程重新回到就绪态,具体包括:在事件等待队列中找到 PCB,让他出队,修改 PCB 的状态信息,再将 PCB 插入到就绪队列,等待 CPU 对他进行调度

一般在等待的事件发生时,进程就会被唤醒。

注意:前面我们说过,进程从阻塞态切换到运行态,是一个被动的过程,这个被动体现在并不是进程自己调用了唤醒原语,而是“合作”进程进行了调用(比如说 I/O 进程)

(5)切换原语

前面的原语主要都是操作一个进程,而切换原语同时操作到了两个进程。

切换原语负责让当前运行的进程从 A 切换为 B,具体包括:

  • 一方面,将 A 的运行环境保存到 PCB 中,再将其 PCB 移入到相应的队列(如果当前进程是从运行态到阻塞态,那么就进入等待队列;如果是从运行态到就绪态,那么就进入就绪队列)

  • 另一方面,选择 B 进程运行,更新其 PCB,同时可能会恢复其运行环境(考虑到 B 进程此前可能曾处于阻塞态)

引起进程切换的事件一般有四种:

  • 当前进程的时间片被消耗完
  • 有更高优先级的进程到达,抢占了当前进程正在使用的 CPU
  • 当前进程主动阻塞
  • 当前进程终止

(6)挂起原语和激活原语

挂起原语:

将进程从内存对换到外存,具体包括:找到需要挂起的进程的 PCB,检查它的状态并做相应操作(运行态、活动就绪态 ——> 静止就绪态,活动阻塞态 ——> 静止阻塞态),之后将该 PCB 复制到指定的内存区域。

引起进程挂起的事件,比如,用户进程请求将自己挂起,或父进程请求将自己的某个子进程挂起

激活原语:

将进程从外存对换回内存,检查该进程的现行状态并进行相应操作(静止就绪态——>活动就绪态,静止阻塞 ——> 活动阻塞态)。引起进程激活的事件,比如,父进程或用户进程请求激活指定进程,或者是某个进程驻留在外存而内存中已有足够的空间

参考:

进程的状态转换


操作系统系列学习笔记:

操作系统学习笔记-1:基础概念

操作系统学习笔记-2:体系结构和运行机制

操作系统学习笔记-3:初识进程和进程控制

操作系统学习笔记-4:进程同步与进程互斥(一)

操作系统学习笔记-5:进程同步与进程互斥(二):信号量机制

操作系统学习笔记-6:进程同步与进程互斥(三):经典问题

操作系统学习笔记-7:进程通信

操作系统学习笔记-8:线程

操作系统学习笔记-9:调度