2.3 进程控制
2.3.1 操作系统内核
通常将一些与硬件紧密相关的模块(如中断处理程序等)、各种常用设备的驱动程序以及运行频率较高的模块(如时钟管理、进程调度和许多模块公用的一些基本操作),都安排在仅靠硬件的软件层次中,将它们常驻内存,即通常被称为OS内核。
目的:
1)便于对这些软件进行保护,防止遭受其他应用程序的攻击
2)可提高OS的运行效率
处理器的执行状态
为了防止OS本身及关键数据(如PCB等)遭受到应用程序有意或无意的破坏,通常也将处理机的执行状态分成系统态和用户态两种:
系统态(管态、核心态) | 用户态(目态) |
较高特权 | 较低特权的执行状态 |
能执行一切指令,能访问所有寄存器和存储区 | 仅能执行规定的指令,访问特定的寄存器和存储区 |
一般情况下,应用程序只能在用户态运行,不能去执行OS指令及访问OS指令。
OS内核基本都包括了两大方面的功能:
1. 支撑功能
支撑功能 – 提供给OS其他众多模块所需要的一些基本功能
1)中断处理 — 内核最基本的功能,OS许多重要的活动,如各种类型的系统调用、键盘命令的输入、进程调度、设备驱动无不依赖于中断。
2)时钟管理 — 内核一项基本功能
时间片轮转调度 — 时间片用完时,便由时钟管理产生一个中断信号,促使调度程序重新进行调度。
在实时系统中的截止时间控制、批处理系统中的最长运行时间控制等
3)原语操作
原语 — 由若干个指令组成,用于完成一定功能的一个过程,区别是“原子操作”,即这个过程是一个不可分割的基本单位,执行过程中不允许中断。
原子操作在操作态下执行,常驻内存。
如用于对链表进行操作的原语、用于实现进程同步的原语等。
2. 资源管理功能
1)进程管理
功能模块运行频率较高 为多种功能模块所需要
进程调度与分派、进程创建和撤销 实现进程同步的原语、常用的进程通信原语
放在内核 — 提高OS性能
2)存储器管理
存储器管理软件的运行频率也比较高 — 如用于实现将用户空间的逻辑地址变换成物理地址的地址转换机构、内存分配和回收的功能模块、实现内存保护和对换功能的模块等。
放在内核中 — 保证存储器管理具有较高的运行速度。
3)设备管理
放在内核 — 由于设备管理和硬件(设备)紧密相关
如各类设备的驱动程序、用于缓和CPU与I/O设备速度不匹配矛盾的缓冲管理、用于实现设备分配和设备独立性功能的模块等。
进程控制是进程管理中最基本的功能。
一般由OS的内核中的原语来实现。
主要包括:
1)创建新进程
2)终止已完成的进程
3)将因发生异常情况而无法继续运行的进程置于阻塞状态
4)负责进程运行中的状态转换
2.3.2 进程的创建
1. 进程的层次结构
OS中,允许一个进程(父进程)创建另一个进程(子进程),由此形成了一个进程的层次结构(进程树)。
1)子进程可以继承父进程所拥有的资源,例如继承父进程打开的文件、父进程分配到的缓冲区等。
2)当子进程被撤销时,应将其从父进程那里获得的资源归还给父进程。
3)此外,在撤销父进程时,也必须同时撤销其所有的子进程。
4)为了标识进程的家族信息 — PCB中设置了家族关系表项 — 标明父进程和所有的子进程。进程不能拒绝子进程的继承权。
值得注意的是,Windows中不存在任何进程层次结构的概念,所有进程都具有相同的地位。
如果一个进程创建另外的进程时,创建进程获得了一个句柄,其作用是可用来控制被创建的进程。但是,这个句柄是可传递的,获得了句柄的进程就拥有控制其他进程的权利。
进程之间不再是层次关系,而是获得句柄与否、控制与被控制的简单关系。
2. 进程图
描述一个进程的家族关系 — 有向树 — 父进程指向子进程
3. 引起创建进程的事件
四类典型事件:
1)用户登录。在分时系统中,用户在中断键入登录命令后,若登录成功,系统将为该用户创建一个进程,并把它插入到就绪队列中。
2)作业调度。在多道批处理系统中,当作业调度程序按一定算法调度到某个(些)作业时,将它们装入内存,为它们创建进程,并把它们插入就绪队列。
3)提供服务。当运行中的用户程序提出某种要求后,系统将专门创建一个进程来提供用户所需要的服务。
要求进行文件打印 — 操作系统创建一个打印进程 — 不仅可使打印进程与该用户进程并发执行,还便于计算为完成打印任务所花费的时间。
4)应用请求。上述三种情况都是系统内核为用户创建一个新进程;而这类事件则是用户进程自己创建新进程,以便使新进程以同创建者进程并发运行的方式完成特定任务。
某用户程序需要不断地先从键盘终端读入数据,继而再对输入数据进行相应的处理,然后,再将处理结果以表格形式在屏幕上显示。为了使这几个操作并发运行,以加速任务完成,可分别创建键盘输入进程、表格输出进程。
4. 进程的创建
系统中出现创建新进程的请求 — OS便调用进程创建原语Creat按以下步骤创建新进程:
1)申请空白PCB,为新进程申请获得唯一的数字标识符(内部标识符),并从PCB集合中索取一个空白PCB
2)为新进程分配其运行所需的资源,包括各种物理和逻辑资源,如内存、文件、I/O设备和CPU时间等 ---- 从操作系统或父进程获得。
新进程对这些资源的需求详情一般也要提前告知操作系统或其父进程。
例如,为新进程的程序和数据以及用户栈分配必要的内存空间时,操作系统必须知道新进程所需内存的大小:
批处理作业 其大小可在用户提出创建进程要求时提供
为应用进程创建子进程 在该进程提出创建进程的请求中给出所需内存的大小
交互型作业 用户可不给出内存要求而由系统分配一定的空间;如果新进程要共享某个已在内存的地址空间(即已装入内存的共享段),则必须建立相应链接
3)初始化进程控制快(PCB)。
包括:
1.初始化标识信息,将系统分配的标识符和父进程标识符填入新的PCB中
2.初始化处理机状态信息,使程序计数器指向程序的入口地址,使栈指针指向栈顶。
3.初始化处理机控制信息,将进程状态设置为就绪状态或静止就绪状态,通常设置为最低优先级,除非用户以显式方式提出高优先级要求。
4)如果就绪队列能够接纳新进程,便将新进程插入就绪队列。
2.3.3 进程的终止
进程的终止
1. 引起终止的事件
引起终止的事件
1)正常结束 — 任何系统中都应有一个用于表示进程已经运行完成的指示
2)异常结束 — 发生了某种异常事件
1越界错 — 程序所访问的存储区,已越出该进程的区域
2保护错 — 程序试图去访问一个不允许访问的资源或文件 或 以不适当的方式进行访问
3非法指令 — 程序试图去执行一条不存在的指令。出现该错误的原因可能是程序错误地转移到数据区,把数据当成了指令
4特权指令错 — 用户程序试图去执行一条只允许OS执行的指令
5运行超时 — 进程执行时间超过了指定的最大值
6等待超时 — 进程等待某事件的时间超过了规定的最大值
7算术运算错 — 进程试图去执行一个被禁止的运算,如被0除
8I/O故障
3)外界干预 — 应外界请求而终止运行
1操作员或OS干预 — 系统中发生了某事件,例如系统死锁,由操作员和OS采取终止某些进程的方式使系统从死锁状态中解救出来
2 父进程请求 — 子进程完成父进程所要求的任务,父进程可提出请求结束子进程
3 因父进程终止 — 所有子进程应当结束
2. 进程的终止过程
终止过程 — 调用终止原语
1.根据被终止进程的标识符,从PCB集合中检索出该进程的PCB,从中读出该进程的状态
2.若被终止进程正处于执行状态,立即终止进程运行,并置调度标志为真,用于指示该进程被终止后应重新进行调度
3.若由子孙进程,应将其子孙进程都予以终止
4.将被终止进程拥有的全部资源归还给系统或父进程
5.将被终止进程(PCB)从所在队列(或链表)中移出,等待其他程序来搜集信息。
2.3.4 进程的阻塞和唤醒
1. 引起进程的阻塞和唤醒的事件
1)向系统请求共享资源失败。
系统无足够资源分配给它,进程不能继续运行而转变为阻塞状态。
2)等待某种操作的完成。
当进程启动某种操作后,如果该进程必须在该操作完成之后才能继续执行,则应先将该进程阻塞起来,以待操作完成。
3)新数据尚未到达。
对于相互合作的进程,如果一个进程需要先获得另一个进程提供的数据才能对其进行处理,只要需要的数据尚未到达,进程便只有阻塞。
4)等待新任务的到达。
某些系统中,特别是在网络环境下的OS,往往设置一些特定的系统进程,每当这种进程完成任务后便把自己阻塞起来,等待新任务的到来。
2. 进程阻塞过程
正在执行的进程,发生了上述事件
1)进程便通过调用阻塞原语block将自己阻塞。可见阻塞是进程自身的一种主动行为。
2)进入block过程后,由于该进程还处于执行状态,所以应先立即停止执行,把进程控制块中的现行状态由“执行”改为阻塞,并将PCB插入阻塞队列
(如果系统中设置了不同事件而阻塞的多个阻塞队列,则应将本进程插入到具有相同事件的阻塞队列)
3)转调度程序进行重新调度,将处理机分配给另一就绪进程,并进行切换(保留被阻塞进程的处理机状态在PCB中,再按新程序的PCB中的处理机状态设置CPU环境)。
3. 进程唤醒过程
当被阻塞进程所期待的事件发生时
由有关进程(比如提供数据的进程)调用唤醒原语wakeup,将等待该事件的进程唤醒
wakeup执行的过程是:
1)首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后再将该PCB插入到就绪队列中
注意,block原语和wakeup原语是一对作用刚好相反的原语,必须成对使用,即如果在某进程中调用了阻塞原语,则必须在与之相合作的、或其他相关的进程中安排一条相应的唤醒原语,以便能唤醒该被阻塞进程;否则,阻塞进程将会因不能被唤醒而永久地处于阻塞状态,再无机会继续运行
2.3.5 进程的挂起和激活
1. 进程的挂起
当系统中出现了引起进程挂起的事件时,OS将利用挂起原语suspend将指定进程或处于阻塞状态的进程挂起。
suspend的执行过程是:
首先检查被挂起进程的状态,若处于活动就绪状态,便将其改为静止就绪;对于活动阻塞状态的进程,则将之改为静止阻塞;
为了方便用户或父进程考查该进程的运行情况,而把该进程的PCB复制到某指定的内存区域;
最后,若被挂起的进程正在执行,则转向调度程序重新调度。
2. 进程的激活过程
当系统中发生激活进程的事件时,OS将利用激活原语active,将指定进程激活。
active的执行过程是:
激活原语先将进程从外存调入内存,检查该进程的现行状态,若是静止就绪,便将之改为活动就绪;若为静止阻塞,便将之改为活动阻塞。
假如采用的是抢占调度策略,则每当有静止就绪进程被激活而插入就绪队列时,便应检查是否要进行重新调度,即由调度程序将被激活的进程与当前进程二者的优先级进行对比 ,如果被激活的进程的优先级低,就不必重新调度;若它高,则重新调度,将处理机分配给刚被激活的进程。
2.4 进程同步
2.4.1 进程同步的基本概念
为保证多个进程能有条不紊低运行,在多道程序系统中,必须引入进程同步机制——硬件同步机制、信号量机制、管程机制
主要任务:对多个相关进程在执行次序上进行协调,使并发执行的诸进程之间能按照一定的规则(或时序)共享系统资源,并能很好地相互合作,从而使程序的执行具有可再现性。
1. 两种形式的制约
两种形式的制约 —— 对于同处于一个系统中的多个进程
1)间接相互制约关系——互斥
多个程序在并发执行时,由于共享系统资源,致使在这些并发执行的程序之间形成相互制约的关系。
对于像打印机、磁带机这样的临界资源,必须保证多个进程对之只能互斥地访问。
由此,在这些进程间形成了源于对该类资源共享的所谓间接相互制约关系。为保证这些进程能有序地运行,对于系统中的这些资源,必须由系统实施统一分配,即用户在要使用之前,应先提出申请,而不允许用户进程直接使用。
2)直接相互制约关系——同步
某些有应用程序,为了完成某任务而建立了两个或多个进程,这些进程将为完成同一项任务而相互合作。
进程间的直接相互制约关系就是源于它们之间的相互合作。
2.临界资源
许多硬件资源如打印机、磁带机等,都属于临界资源,诸进程间应采取互斥方式,实现对这种资源的访问。
3. 临界区
临界区 —— 每个进程中访问临界资源的那段代码
每个进程在进入临界区之前,应先对欲访问的临界资源进行检查,看其是否正被访问。如果此刻临界资源未被访问,进程便可进入临界区对该资源进行访问,并设置它正被访问的标志;如果此刻该临界资源正被访问,则本进程不能进入临界区。
所以,必须在临界区前面增加一段用于进行上述检查的代码 —— 进入区,相应地,在临界区后面增加一段用于将临界区正被访问的标志恢复为未被访问的标志 —— 退出区,除了上述之外的其他部分的代码 —— 剩余区
while(TRUE) { 进入区(entry section); 临界区(critical section); 退出区(exit section); 剩余区(remainder section); }
4. 同步机制四条准则
同步机制四条准则:
空闲让进 | 当无程序处于临界区,表明临界资源处于空闲状态,应允许一个请求进入临界区的进程立即进入临界区,以有效地利用临界资源 |
忙则等待 | 当已有进程进入临界区时,表明临界资源正在被访问,因而其他试图进入临界区的进程必须等待,以保证对临界资源的互斥访问 |
有限等待 | 对要求访问临界资源的进程,应保证在有限时间内能进入自己的临界区,以免陷入 “死等” 状态 |
让权等待 | 当进程不能进入自己的临界区时,应立即释放处理机,以免进程陷入 “ 忙等” 状态 |
2.4.2 硬件同步机制
软件方法解决互斥进入临界区 —— 有一定难度,并且存在很大的局限性,现已很少采用
硬件方法 —— 利用计算机提供的一些特殊的指令来解决临界区问题,但当临界资源忙碌时,其他访问进程必须不断地进行测试,处于一种“忙等”状态,不符合“忙等让权”的原则,造成处理机时间的浪费,同时也很难将它们用于解决复杂的进程同步问题
在对临界区进行管理时,可将标志看做一个锁,初始时锁是打开的。
每个要进入临界区的进程必须先对锁进行测试,锁未开等待直至锁开,锁开立即将其锁上。
为防止多个进程同时测试到锁为打开的情况,测试和关锁操作是连续的,不允许分开进行。