HICSC
004 进程管理:进程控制

进程控制是进程管理中最基本的功能,通过这个功能来控制一个进程的生死。简单来说,就是进程在何种情况下由某种状态转换为另一种状态的这一过程就是进程管理的主要功能。比如,它可以创建一个新进程,也可以终止一个已完成的进程。

进程控制一般是由操作系统内核原语来实现的。

原语(Primitive)是由若干条指令组成的,用于完成特定功能的一个过程,其作用是为了实现进程的通信与控制。

进程的创建

首先,需要注意的一点是,进程是存在父子关系的,比如,在A进程中创建了B进程,那么A就是B的父进程,B就是A的子进程。子进程可以继承父进程所拥有的资源,比如继承父进程打开的文件,继承父进程所分配到的缓冲区等等。

当子进程被撤销时,应将其从父进程那儿获得的资源归还给父进程,而撤销父进程时,也必须同时撤销其所有的子进程。为了标记进程间的父子关系,在PCB中设置了家族关系表项,用于标明自己的父进程与所有子进程。

为了使程序可以独立运行,就必须为其创建进程,导致进程创建的典型事件有以下四类:

  1. 用户登录:用户在终端输入登录命令后,如果用户合法,系统将为该终端创建一个进程。
  2. 作业调度:操作系统作业调度程序按一定算法调度到某作业时,就会为其创建一个进程。
  3. 提供服务:用户程序请求操作系统为其提供某项服务,比如,用户程序要求打印文件,系统就会为其创建一个打印进程。
  4. 应用请求:应用程序基于自己的需求,自己创建一个新进程来完成特定任务。

当操作系统接收到上述进程创建的事件后,便调用进程创建原语Create,按下面的步骤创建一个新进程。

  1. 申请空白PCB:为新进程申请唯一数字标识符,并从PCB集合中取得一个空白PCB。
  2. 为进程分配资源:主要是内存空间。
  3. 初始化PCB:主要是初始化处理机的状态信息和控制信息。
  4. 将新进程插入就绪队列。

进程的终止

在三种情况下,进程会被终止,一是正常结束,二是因出现错误或故障,三是响应外界的请求。

当一个进程已经运行完成,会产生一个中断,通知操作系统自己已经完成了所有工作,操作系统将择机终止该进程,这样的进程属于正常结束。

异常结束是指在运行过程中,出现了错误和故障而被迫终止,这样的事件有很多,比如:越界错误、保护错误 (进程试图访问一个被保护的资源或文件)、非法指令、运行超时、I/O故障等等。

另外还有一种情况是进程并没有出现异常情况,只是单纯的响应外界的请求而终止运行,比如:

  1. 用户或操作系统干预:基于某种原因,比如死锁,用户和操作系统终止了该进程。
  2. 父进程请求:父进程可终止自己的所有子孙进程。
  3. 父进程终止:父进程被终止时,其所有子孙进程都将被终止。

如果系统中发生了上述要求终止进程的事件,操作系统便调用进程终止原语,终止制定进程:

  1. 根据PID从PCB集合中找到对应进程的PCB,从中读取该进程的状态
  2. 终止该进程
  3. 若还有子孙进程,一并终止
  4. 归还被终止进程所拥有的全部资源
  5. 将被终止进程从所在队列中移除,等待其他程序来搜集信息

进程的阻塞与唤醒

当进程执行过程中遇到以下情况时会被阻塞,然后被唤醒:

请求系统服务

当正在执行的进程请求操作系统提供服务时,但操作系统并不能立即满足时,该进程只能转变为阻塞状态来等待。还是那个例子,当进程请求打印机时,由于系统已将打印机分配给其他进程,请求者只能被阻塞,当其他进程释放打印机后,该进程才会被唤醒。

启动某种操作

当进程启动某种操作后,如果该进程必须在该操作完成之后才能继续执行,则必须先 使该进程阻塞,以等待该操作完成。比如,I/O操作,当进程启动某I/O设备后,便自动进入阻塞状态去等待,直到I/O设备完成了指定的I/O操作任务后,进程才能被唤醒。

任务需要相互配合

多个进程需要相互合作去完成某些任务时,如果其中一个进程需要先获得另外一个合作进程提供的数据后才能继续执行,在数据尚未达到时,该进程只有阻塞等待。还有一类进程,定时在后台执行特定功能,当指定操作执行完成后,便阻塞自己,等到下一时刻需要再次执行时,又重新唤醒自己。还有一种常见的例子就是生产者和消费者问题,当队列中没有任务可处理时,消费者就会阻塞自己,等到队列中有任务时,又会重新唤醒自己。

进程的阻塞与唤醒过程

正在执行的进程,当发现上述事件时,由于无法继续执行,进程便通过调用阻塞原语block把自己阻塞。可见,进程的阻塞是进程自身的一种主动行为。整个阻塞过程也分为三个步骤::

  1. 更新PCB状态:如果进程正在执行,则需要立即停止执行,把PCB中的状态由「执行」改为「阻塞」。
  2. 将PCB插入到阻塞队列中:如果系统还设置了因不同事件导致阻塞的多个队列,则需要根据具体的阻塞事件插入对应的阻塞队列中。
  3. 调度程序重新调度:将进程转给调度程序重新调度,并将处理机分配给另一就绪进程并进行切换。同时,还要保留被阻塞进程的处理机状态在PCB中,再按新进程的PCB中的处理机状态设置CPU环境。

当被阻塞进程所期待的事件出现时,比如I/O已完成或打印机已归还等,则由相关进程(释放I/O设备的进程)调用唤醒原语wakeup,将等待该事件的进程唤醒。整个唤醒过程也分为三个步骤:

  1. 把被阻塞的进程从等待该事件的阻塞队列中移出
  2. 将其 PCB 中的现行状态由「阻塞」改为「就绪」
  3. 将该 PCB 插入到就绪队列中

这里需要注意的一点时,block原语和wakeup原语必须成对出现,如果某进程调用了block原语,则必须在与之合作的另一进程或其他相关的进程中调用wakeup原语,以便唤醒阻塞进程。否则,被阻塞进程将会因不能唤醒而一直阻塞,也没有机会再继续运行。

进程的挂起与激活

当出现引起进程挂起的事件时,系统将调用挂起原语suspend将进程挂起,比如,进程自己请求挂起,或父进程请求将自己的某个子进程挂起。进程的挂起过程分为3个步骤:

  1. 检查并修改进程状态:若处于活动就绪状态,便将其改为静止就绪; 对于活动阻塞状态的进程,则将之改为静止阻塞。
  2. 复制进程PCB到指定内存区域:为方便用户或父进程检查进程运行情况,会把该进程PCB复制到某指定内存区域。
  3. 重新调度:若被挂起的进程正在执行,则转向调度程序重新调度。

同理,当出现激活进程的事件时,系统将调用激活原语active将进程激活,比如,父进程或用户进程请求激活指定进程。整个激活流程分为4个步骤:

  1. 检查内存资源:如进程驻留外存,且内存空间足够,则可将在外存上处于静止就绪状态的该进程换入内存。
  2. 检查并修改进程状态:检查该进程的现行状态,若是静止就绪,便将之改为活动就绪;若为静止阻塞,便将之改为活动阻塞。
  3. 重新调度:如果采用的是抢占调度策略,则每当有新进程进入就绪队列时,应检查是否要进行重新调度,即由调度程序将被激活进程与当前进程进行优先级的比较,如果被激活进程的优先级更低,就不必重新调度;否则,立即剥夺当前进程的运行,把处理机分配给刚被激活的进程。

结语

进程的管理是比较简单的概念,但确是整个进程管理中最核心的功能。在学习时,只要抓住最核心的一点即可,进程控制,控制什么?就是控制进程在何种情况下由何种状态转换为另外的状态。至于引起状态转换的这些事件,了解就好,也没什么必要去记忆,毕竟对于不同的操作系统,这些事件也不一致,而且随着操作系统的不断发展,未来也会有很大的变化。

Comments

Post a Message

人生在世,错别字在所难免,无需纠正。

提交评论