写在前面:
这一部分开始学习进程的控制.进程控制是进程管理中最基本的功能.它用于创建一个新进程,终止一个已完成的进程,或终止一个因出现某事件而无法运行下去的进程,还可以负责进程运行中的状态转换.进程控制一般是由OS的内核中的原语来实现的.
原语:
原语(Primitive)是由若干条指令组成的,用于完成一定功能的一个过程.它是”原子操作(Action Operation)”.原子操作的含义就是,一个操作中的所有动作要么全做,要么全不做,因此它是一个不可分割的基本单位.因此,在执行过程中不允许被中断.原子操作在管态下执行,常驻内存.原语的作用是为了实现进程的通信和控制,如果系统不适用原语,就会造成进程状态的不确定性.从而无法控制进程.
进程的创建:
(1)进程图:
进程图是用于描述一个进程的家族关系的有向树.具体如下所示:
图1,进程树
子进程可以继承父进程所拥有的资源,比如父进程打开的文件,继承父进程所分配到的缓冲区等.当子进程被撤销时,其从父进程获得的资源都将归还给父进程.当父进程被撤销时,必须同时撤销其所有的子进程.PCB中有设置家族关系表项,来表明进程之间的家族关系.
(2)引起进程创建的事件:
为使程序运行,必须为其创建进程.导致一个进程去创建另一个进程的典型事件有以下四类:
- 用户登录:在分时系统中,用户在终端键入登陆命令后,若为合法用户,系统将为该终端创建进程,并将其插入到就绪队列中.
- 作业调度:在批处理系统中,当作业调度程序按一定的算法调度到某作业时,便将该作业装入内存,为它分配必要的资源,并立即为它创建进程,再插入就绪队列中。
- 提供服务:当运行中的用户程序提出某种请求后,系统将专门创建一个进程来提供用户所需要的服务.
- 应用请求:基于应用进程的需求,由它自己创建一个新进程,以便使新进程以并发运行方式完成特定任务。
(3)进程的创建:
一旦操作系统发现了要求创建新进程的事件后,便调用进程创建原语 Creat( )按下述步骤创建一个新进程:
- 申请空白 PCB。为新进程申请获得惟一的数字标识符,并从 PCB 集合中索取一个空白 PCB。
- 为新进程分配资源。为新进程的程序和数据以及用户栈分配必要的内存空间。此时操作系统必须知道新进程所需内存的大小。
- 初始化PCB。PCB 的初始化包括:① 初始化标识信息,将系统分配的标识符和父进程标识符填入新 PCB 中;② 初始化处理机状态信息,使程序计数器指向程序的入口地址,使栈指针指向栈顶;③ 初始化处理机控制信息,将进程的状态设置为就绪状态或静止就绪状态,对于优先级,通常是将它设置为最低优先级,除非用户以显式方式提出高优先级要求.
- 将新进程插入就绪队列,如果进程就绪队列能够接纳新进程,便将新进程插入就绪队列.
进程的终止:
(1)引起进程终止的事件有:
- 正常结束:在任何计算机系统中,都应有一个用于表示进程已经运行完成的指示。
- 异常结束:在进程运行期间,由于出现某些错误和故障而迫使进程终止(Termination of Process)。这类异常事件常见的有以下8类:
(1)越界错误。这是指程序所访问的存储区已越出该进程的区域。
(2)保护错。这是指进程试图去访问一个不允许访问的资源或文件,或者以不适当的方式进行访问,例如,进程试图去写一个只读文件。
(3)非法指令。这是指程序试图去执行一条不存在的指令。出现该错误的原因,可能是程序错误地转移到数据区,把数据当成了指令。
(4)特权指令错。这是指用户进程试图去执行一条只允许 OS 执行的指令。
(5)运行超时。这是指进程的执行时间超过了指定的最大值。
(6)等待超时。这是指进程等待某事件的时间超过了规定的最大值。
(7)算术运算错。这是指进程试图去执行一个被禁止的运算,例如被 0 除。
(8) I/O 故障。这是指在 I/O 过程中发生了错误等。 - 外界干预 :外界干预并非指在本进程运行中出现了异常事件,而是指进程应外界的请求而终止运行。这些干预有:
(1)操作员或操作系统干预。由于某种原因,例如,发生了死锁,由操作员或操作系统终止该进程。
(2)父进程请求。由于父进程具有终止自己的任何子孙进程的权力,因而当父进程提出请求时,系统将终止该进程。
(3)父进程终止。当父进程终止时,OS 也将它的所有子孙进程终止。
(2)进程的终止过程:
如果系统中发生了上述要求终止进程的某事件,OS 便调用进程终止原语,按下述过程去终止指定的进程。
(1) 根据被终止进程的标识符,从 PCB 集合中检索出该进程的 PCB,从中读出该进程的状态。
(2) 若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标志为真,用于指示该进程被终止后应重新进行调度。
(3) 若该进程还有子孙进程,还应将其所有子孙进程予以终止,以防它们成为不可控的进程。
(4) 将被终止进程所拥有的全部资源,或者归还给其父进程,或者归还给系统。
(5) 将被终止进程(PCB)从所在队列(或链表)中移出,等待其他程序来搜集信息。
进程的阻塞与唤醒:
(1)引起进程阻塞和唤醒的事件有:
- 请求系统服务:当正在执行的进程请求操作系统提供服务时,由于某种原因,操作系统并不立即满足该进程的要求时,该进程只能转变为阻塞状态来等待。
- 启动某种操作:当进程启动某种操作后,如果该进程必须在该操作完成之后才能继续执行,则必须先使该进程阻塞,以等待该操作完成。
- 新数据尚未到达:对于相互合作的进程,如果其中一个进程需要先获得另一(合作)进程提供的数据后才能对数据进行处理,则只要其所需数据尚未到达,该进程只有(等待)阻塞。
- 无新工作可做:系统往往设置一些具有某特定功能的系统进程,每当这种进程完成任务后,便把自己阻塞起来以等待新任务到来。
(2)进程阻塞过程:
当发生进程阻塞事件后,进程调用阻塞原语 block 把自己阻塞。可见,进程的阻塞是进程自身的一种主动行为。进入 block 过程后,由于此时该进程还处于执行状态,所以应先立即停止执行,把进程控制块中的现行状态由“执行”改为“阻塞”,并将 PCB 插入阻塞队列。如果系统中设置了因不同事件而阻塞的多个阻塞队列,则应将本进程插入到具有相同事件的阻塞(等待)队列。最后,转调度程序进行重新调度,将处理机分配给另一就绪进程并进行切换,亦即,保留被阻塞进程的处理机状态(在 PCB 中),再按新进程的 PCB 中的处理机状态设置 CPU 的环境。
(3)进程唤醒过程:
当被阻塞进程所期待的事件出现时,如 I/O 完成或其所期待的数据已经到达,则由有关进程(比如用完并释放了该 I/O 设备的进程)调用唤醒原语 wakeup( ),将等待该事件的进程唤醒。唤醒原语执行的过程是:首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB 中的现行状态由阻塞改为就绪,然后再将该 PCB 插入到就绪队列中。
应当指出,block 原语和 wakeup 原语是一对作用刚好相反的原语。因此,如果在某进程中调用了阻塞原语,则必须在与之相合作的另一进程中或其他相关的进程中安排唤醒原语,以能唤醒阻塞进程;否则,被阻塞进程将会因不能被唤醒而长久地处于阻塞状态,从而再无机会继续运行。
进程的挂起与激活:
(1)进程的挂起:
当出现了引起进程挂起的事件时,比如,用户进程请求将自己挂起,或父进程请求将自己的某个子进程挂起,系统将利用挂起原语 suspend( )将指定进程或处于阻塞状态的进程挂起。挂起原语的执行过程是:首先检查被挂起进程的状态,若处于活动就绪状态,便将其改为静止就绪; 对于活动阻塞状态的进程,则将之改为静止阻塞。为了方便用户或父进程考查该进程的运行情况而把该进程的 PCB 复制到某指定的内存区域。最后,若被挂起的进程正在执行,则转向调度程序重新调度。
(2)进程的激活过程:
当发生激活进程的事件时,例如,父进程或用户进程请求激活指定进程,若该进程驻留在外存而内存中已有足够的空间时,则可将在外存上处于静止就绪状态的该进程换入内存。这时,系统将利用激活原语 active( )将指定进程激活。激活原语先将进程从外存调入内存,检查该进程的现行状态,若是静止就绪,便将之改为活动就绪;若为静止阻塞,便将之改为活动阻塞。假如采用的是抢占调度策略,则每当有新进程进入就绪队列时,应检查是否要进行重新调度,即由调度程序将被激活进程与当前进程进行优先级的比较,如果被激活进程的优先级更低,就不必重新调度;否则,立即剥夺当前进程的运行,把处理机分配给刚被激活的进程。