进程控制
# 进程控制
进程控制由 “原语” 实现。原语具有 “原子性”,要么不被执行,一旦被执行,不可以被中断。
在关中断指令下,即使有中断信号发射过来,也不会调用中断处理程序去处理中断,这就保证了原语操作不会被打断。而在开中断指令下,才会去处理中断。
原语的基本操作包括:
- 更新 PCB 中的信息(修改进程状态标志、保存当前运行环境到 PCB、从 PCB 中恢复运行环境)
- 将 PCB 插入到合适的队列
- 分配 / 回收资源
创建原语和撤销原语配对,阻塞原语和唤醒原语配对。
进程的执行是 “异步” 的,进程的控制是 “原子性” 的。
# 进程的状态转换
# 三态
阻塞态的进程不会立即转为执行态。阻塞态和就绪态的进程在内存中,执行态的进程在 CPU 中。
# 五态
创建进程的过程在内存里完成。
# 七态(重要,在后面的章节会有所拓展)
# 静止阻塞 / 就绪队列的理解
当我们把作业从外存拿到内存时,这个过程叫做高级调度。
进程 PCB 被创建后,PCB 存在内存中,创建的过程在内存中实现;进程创建完成后,如果所需的资源除了内存之外都满足,则进程被对换到静止就绪队列,不参与调度,此时进程创建工作完成。
如果静止阻塞队列中的进程,内存资源得到满足,但是阻塞的原因仍未解除,则从静止阻塞队列进入活动阻塞队列。
如果静止就绪队列中的进程,内存资源得到满足,则从静止就绪队列进入活动就绪队列。
# 挂起的原因
负荷调节的需要、终端用户的请求、父进程请求、操作系统的需要
# 挂起的特征
- 该进程不能立即被执行
- 挂起进程可能会等待事件,但所等待事件是独立于挂起条件的,事件结束并不能导致进程具备执行条件
- 进程进入挂起状态是由于操作系统父进程或进程本身阻止它的运行
- 结束进程挂起状态的命令只能通过操作系统或父进程发出
# 状态转换的汇总
状态 | 解释 |
---|---|
活动就绪态 → 静止就绪态 | 操作系统根据当前资源状况和性能要求,可能会把活动就绪态对换出去,成为静止就绪态。处于静止就绪态的进程不再被调度执行; |
静止就绪态 → 活动就绪态 | 内存中没有进程处于活动就绪态,或者处于静止就绪态的进程具有更高的优先级,那么静止就绪态就会被对换回来,此时才可能被调度执行 |
活动阻塞态→ 静止阻塞态 | 操作系统根据当前资源状况和性能要求,可能会把活动阻塞态对换出去,成为静止阻塞态。 |
静止阻塞态→ 静止就绪态 | 常见的情况是,引起进程等待的事件发生之后,相应的静止阻塞态进程将转换为静止就绪态 |
静止阻塞态→ 活动阻塞态 | 但有时候,如果静止阻塞态进程的优先级高于静止就绪队列中的任何进程、并且系统有把握它等待的事件即将完成,那么就会激活为活动阻塞态 |
运行态→ 静止就绪态 | 优先级较高的静止阻塞态在等待的事件完成后,可能会抢占 CPU,若此时资源不够,则可能导致正在运行的进程挂起为静止就绪态 |
创建态→ 静止就绪态 | 操作系统根据当前资源状况和性能要求,可能会在进程创建完就把它对换到外存 |
进程一旦被挂起,就意味着它被对换到了外存中,此时该进程无法再被 CPU 直接调度,除非它被对换回内存中,回到活动就绪态。比如静止就绪态、静止阻塞态,最后要得到 CPU 的调度,都必须经历回归到活动就绪态的过程。
# 进程的创建(创建原语)
- 申请空白 PCB
- 为新进程分配其运行所需的资源
- 初始化 PCB
- 如果进程就绪队列能够接纳新进程,便将新进程插入就绪队列。如果是三态或五态,进程转入就绪态;如果是七态,储存在内存中的为活动就绪态,储存在外存中的为静止就绪态。
# 进程的终止(撤销原语)
引起进程终止的事件包括正常结束、异常结束和外界干预。
终止进程的过程包括:从 PCB 集合中找到终止进程的 PCB,如果进程正在运行,则立即将它的 CPU 使用权移交给其它进程。接着终止它的所有子进程,将该进程的资源还给父进程或者操作系统,最后再删除 PCB。
- 进入终止态的进程不能再执行
- OS 中保留其记录(状态码 + 计时统计数据),供其他进程收集
- 一旦其他进程完成了对终止状态进程的信息提取,OS 将删除该进程
# 进程的阻塞(阻塞原语 block)
阻塞进程的过程包括:找到要阻塞的进程的 PCB,保存当前运行环境到 PCB(方便后续恢复),修改 PCB 状态信息。接着暂停进程的运行,将 PCB 插入相应事件的阻塞队列(即改变它的链接地址)。
引起进程阻塞的事件一般是:
- 请求系统分配共享资源失败(系统已无足够的资源)
- 等待某种操作的完成。如请求系统某些服务(比如打印服务)和启动某种操作(比如 I/O 操作)
- 新数据尚未到达
- 等待新任务的到达
进程从运行态切换到阻塞态是一种主动行为,这个主动体现在是进程自己调用了阻塞原语。
# 进程的唤醒(唤醒原语 wake up)
唤醒进程的过程包括:在事件阻塞队列中找到 PCB 并将进程移出队列,修改 PCB 的状态信息,再将 PCB 插入到就绪队列。
一般在等待的事件发生时,进程就会被唤醒。
阻塞原语和唤醒原语是一对作用刚好相反的原语,必须成对使用。进程从阻塞态切换到运行态,是一个被动的过程,这个被动体现在并不是进程自己调用了唤醒原语,而是 “合作” 或相关进程进行了调用。
# 进程的切换(切换原语)
前面的原语主要都是操作一个进程,而切换原语同时操作到了两个进程。
切换原语负责让当前运行的进程从 A 切换为 B,具体包括:
- 一方面,将 A 的运行环境保存到 PCB 中,再将其 PCB 移入到相应的队列(如果当前进程是从运行态到阻塞态,那么就进入阻塞队列;如果是从运行态到就绪态,那么就进入就绪队列)
- 另一方面,选择 B 进程运行,更新其 PCB,同时可能会恢复其运行环境(考虑到 B 进程此前可能曾处于阻塞态)
引起进程切换的事件一般有四种:
- 当前进程的时间片被消耗完
- 有更高优先级的进程到达,抢占了当前进程正在使用的 CPU
- 当前进程主动阻塞
- 当前进程终止
# 进程的挂起(挂起原语 suspend 和激活原语 active)
挂起原语:
将进程从内存对换到外存,具体包括:找到需要挂起的进程的 PCB,检查它的状态并做相应操作(活动就绪态 -> 静止就绪态,活动阻塞态 -> 静止阻塞态),之后将该 PCB 复制到指定的内存区域。若被挂起的进程正在执行,则转向调度程序重新调度。
引起进程挂起的事件,比如用户进程请求将自己挂起,或父进程请求将自己的某个子进程挂起。
激活原语:
将进程从外存对换回内存,检查该进程的现行状态并进行相应操作(静止就绪态 -> 活动就绪态,静止阻塞 -> 活动阻塞态)。
引起进程激活的事件,比如,父进程或用户进程请求激活指定进程,或者是某个进程驻留在外存而内存中已有足够的空间。