Skip to content

Latest commit

 

History

History
340 lines (190 loc) · 19.7 KB

进程常见知识点总结.md

File metadata and controls

340 lines (190 loc) · 19.7 KB

进程常见知识点总结

不管是工作面试还是应试考试,进程都是操作系统中非常重要的一环,因为进程是操作系统进行资源分配的基本单位,同时进程也是相对于操作系统来说可以独立运行的基本单位,本文将向大家详细介绍进程的前世今生以及风流韵事。 本文主要内容如下: 在这里插入图片描述

前趋图&程序执行

我们首先来分析一下为什么操作系统要引入进程这个概念,即进程从哪来?

一般来说,操作系统按照是否支持并发可分为以下两类:

  1. 早起的计算机大多数都是单道批处理系统,即每一个时刻最多只能有一道用户程序被装入内存中执行、其他用户程序只能等待,这样的机制使得计算机的资源得不到充分利用、系统吞吐率低下。
  2. 后来的多道程序系统中正式支持多道用户程序的同时执行,使得系统资源的利用率得到了大幅提高。

这两种不同的程序运行机制有着很大的不同,尤其是资源分配方面,在单道批处理系统中,每一时刻运行的用户程序最多只有一个,这时资源很好分配,只需要把系统所有资源都分配给正在运行的那一个用户程序即可。可是多道程序系统呢?同一时刻可能有多个用户程序都在运行,如何合理地将有限的系统资源分配给这些用户程序?以什么单位进行资源的分配?为了解决这一系列的问题,引入了操作系统中进程的概念,所以,在对进程做深入了解之前,我们先介绍一下程序的顺序执行和并发执行,从这两种不同的程序执行方式中寻找进程的来源。

前趋图

前趋图实际上是一个有向无环图(DAG,Directed Acyclic Graph),描述的是多个进程的执行顺序,如下图所示:

image-20190701143809203

在前趋图中,每个结点代表一个进程(如上面的4个圆),箭头表示了进程之间的执行顺序,比如上图所示的前趋图表示要求ABCD四个进程需要按照$A \to B \to C \to D$的顺序进行执行。

前趋图可以使用式子进行抽象表示,比如上图表示的进程间关系可以描述为: $$ A \to B,B\to C,C\to D \space 或\ (A,B),(B,C),(C,D) $$ 注意,前趋图中不能有循环,即回路,否则必然会出现冲突,比如像下图:

image-20190701144150877

具有回路,边1要求A在B之前执行,边2要求B在A之前执行,这显然永远不可能实现,即具有冲突。

程序顺序执行

程序顺序执行很好理解,就是多个程序按照指定顺序串行进行执行,反映到前趋图上就是:

image-20190701143809203

表示ABCD四个程序会串行顺序进行执行。

我们可以发现程序顺序执行具有以下几个特点:

  1. 顺序性:处理机严格按照指定的顺序执行
  2. 封闭性:程序会在封闭的环境下运行,运行时独占系统资源,结果不受其他程序干扰
  3. 可再现性:只要程序执行时的环境与初始条件相同,不管执行多少次程序,最后的结果一定是一样的

程序并发执行

程序顺序执行导致计算机资源利用率过低,解决办法就是引入程序并发执行,但是很明显不是所有程序都可以并发执行,如果两个程序具有前趋关系,这两个程序一定不可能并发执行。

我们举个例子,比如有4个应用程序,每一个应用程序所做的工作如下:

S1:

a:=y+2

S2:

b:=y+4

S3:

c:a+b

S4:

d:=c+b

很明显,在执行S3之前必须知道ab的值即S1S2必须执行完成,在执行S4的时候必须知道c和``bS3S2必须完成,而S1S2之间没有前趋关系,可以并发执行以提高效率,这样抽象出来前趋图为:

image-20190701150017122

可以看到,S1和S2就可以并发执行,这样可以提高系统的资源利用率。

那么并发执行有什么特点呢?总结一下大概有3条:

  1. 间断性:比如上面的例子,S1和S2是并发执行的,有可能S1执行了1s就执行完成了,但是S2需要执行3s才能完成,由于S1和S2都完成的前提下S3才能运行,所以会导致S2等待S1执行完成,即S2需要暂停,这就导致了并发程序具有“执行——暂停——执行”这种间断性的活动规律。

  2. 失去封闭性:当多个程序进行并发执行时,每一个程序都有可能影响系统的资源状态,进而间接影响到其他正在运行的程序的状态,比如S1运行的时候由于运算量太大导致占用系统资源过渡,进而S2没有可用资源,S2就必须暂停等待系统的空闲资源,即S1的运行将S2的状态从运行中影响到等待中。

  3. 不可再现性:由于并发程序运行时失去了封闭性,所以不能保证程序运行的可再现性,即同一个程序多次执行的结果可能不一致,比如有程序A和程序B并发执行,二者共同操作变量N,A的操作是:N=N+1;,B的操作是Printf(N);N=0;,即:

    image-20190701151655927

    由于并发执行时程序的运行速度受系统资源影响(没有封闭性导致的),所以有可能发生的情况有:

    image-20190701152315229

    如上图所示,可以看到,由于并发,会产生多种可能的代码执行顺序,进而产生多种执行结果,即程序的运行结果不可再现(不要杠精上线说上图2、3两个执行顺序执行结果一样哦)。

看到这里有的读者可能会有疑问,既然都不能保证运行结果的唯一性,程序的并发执行还有意义吗?是的,我们一定是想让我们的程序在执行的时候可以产生唯一结果、不受其他程序影响、而且具有可再现性,所以我们就需要解决这个问题,聪明的读者已经猜出来如何解决了,是的,就是进程

进程的描述

进程的定义和特征

进程的定义

本节主要介绍进程的定义。

首先再明确一下引入进程的目的:使程序可以并发执行,对并发执行的程序加以描述和控制

其次我们我们来看一下进程的组成部分:

image-20190701154918974

可以看到,进程实体(进程映像,简称进程)由程序段相关的数据段、**进程控制块(PCB)**三部分组成,程序段、相关的数据段都很好理解,那什么是进程控制块呢?

为了使参与并发执行的每个程序(含数据)都能独立运行,在操作系统中必须为之配置一个专门的数据结构,称之为进程控制块(Process Control Block,PCB),系统利用PCB来描述进程的基本情况和活动过程,进而控制和管理进程。

另外提醒一点,一般情况下,所谓的创建进程实际上指的是创建进程实体中的PCB,而撤销进程实际上指的是撤销进程的PCB

现在我们可以对进程做一个正式的定义了:进程是进程实体的运行过程,是系统进行资源分配和调度的独立单位

进程的特征

要明确,进程和应用程序是两个截然不同的概念,进程有PCB,而应用程序没有,此外,进程还具有以下特征(附有普通应用程序和进程的区别):

image-20190701160525878

进程的基本状态及转换

在上一节我们提到进程具有动态性的特点,即进程就有一定的声明周期,那么在进程声明周期的不同阶段进程会处于不同的状态,一般来说,进程的具有两类、五个状态,如下图所示:

image-20190701161409654

基本状态

进程有三种基本状态:

  1. 就绪(Ready)状态:进程获取了除CPU资源之外的所有必须资源后的状态(如果系统中有多个进程都处于就绪状态,通常按照一定的优先策略将他们排成一个队列,该队列称为就绪队列
  2. 执行(Running)状态:进程已经获取了所有资源(包括CPU资源),当前正在运行。
  3. 阻塞状态(Block):正在执行的进程由于某些事件(比如I/O请求、申请缓冲区失败等)暂时无法继续执行的状态,也称进程的执行受到阻塞(阻塞状态、等待状态、封锁状态),当有多个进程处于阻塞状态时,也会将这些阻塞状态的进程排成一个或多个阻塞队列。

那么进程的这三种状态时如何转化的呢?一图胜千言,直接看图:

image-20190701163741817

其他状态

除了以上的三种基本状态,进程还具有一下两种常见的状态:

  1. 创建状态
  2. 终止状态
创建状态

创建进程是一个很复杂的过程,要经历多个步骤:

  1. 申请空白PCB
  2. 向PCB填写用于控制和管理进程的信息
  3. 为进程分配运行时所必须的资源
  4. 将进程转为就绪状态
  5. 将进程插入就绪队列

那么这么多步能保证一次立马顺序执行完吗?答案当然是不能,由于系统资源的动态性,创建进程的过程有可能出现暂停、等待,但是此时进程的创建还没有完成,即进程还不能被调度运行,此时的进程处于的状态就是创建状态。

通过创建状态的引入,操作系统可以根据系统性能或主存容量的限制推迟新进程的提交(创建状态),而当进程获取了所有必须资源后,即可由创建状态转入就绪状态。

终止状态

进程的终止也是一个较为复杂的过程,要经历两步:

  1. 等待操作系统进行善后处理
  2. 将PCB清零、PCB空间返还系统

进程进入终止状态后不能再继续执行,但在操作系统中依然保留一个记录,其中保存状态码和一些计时统计数据,供其他进程收集。一旦其他进程完成了对其信息的提取,操作系统即删除该进程,即将PCB清零,将空白PCB返还给操作系统。

下图展示了引入创建状态和终止状态后的进程状态转换图:

image-20190701164926560

挂起操作和进程状态的转换

在许多操作系统中,还可以对进程执行挂起操作,该操作作用于某个进程时,该进程将被挂起,意味着此时该进程处于静止状态,如果进程正在执行,它将暂停执行,若原本处于就绪状态,则该进程此时暂不接受调度。与挂起操作相对应的是激活操作

挂起操作主要发生在以下几个场景:

  1. 终端用户需要
  2. 父进程的请求
  3. 负荷调节的需要
  4. 操作系统的需要

挂起操作一般是通过Suspend原语进行实现的,而激活操作是通过Active原语进行实现的。

引入了挂起和激活操作之后衍生出了以下几种状态:

image-20190701172757999

而这些状态之间的转换关系可用下图表示:

IMG_20190701_173104R

进程管理中的数据结构

image-20190701202055110

如上图是操作系统控制表的一般结构,此处我们重点介绍一下操作系统所管理的进程表,即进程控制块PCB。

PCB的作用

总的来说,进程控制块(Process Control Block)的作用是:使一个在多道程序环境下不能独立运行的程序(含数据)成为一个能独立运行的基本单位、一个能与其他进程并发执行的进程。具体地,可将PCB的作用细分为一下几部分:

image-20190701203253244

从PCB的作用我们可以看出,PCB的的很多功能都是基于PCB中存储的信息才能实现的,那么PCB中都存储有哪些信息呢?

PCB中的信息

简单来说PCB中主要包括四方面信息:

image-20190701204551632

PCB的组织方式

在一个操作系统中,可能同时存在很多个PCB(成百上千个),操作系统是以何种方式管理、组织这些PCB的?目前常用的组织方式有以下三种:

image-20190701205626565

进程控制

所谓的进程控制,其实主要指的是以下几部分:

image-20190701210011238

而这些功能一般是借助操作系统内核中的原语来进行实现的,我们先来了解一下操作系统内核。

操作系统内核

什么是操作系统内核:现代操作系统一般将OS划分为不同的层次,然后将OS的不同功能别别放置到不同的层次中。通常将一些与硬件紧密相关的模块(如中断处理程序)、各种常用设备的驱动程序、运行频率较高的模块(如时钟管理)都安排在紧靠硬件的软件层中,将他们驻留在内存中,即通常所说的OS内核

将OS内核部分驻留在内存中主要是出于两个目的:

  1. 便于对内核进行保护、防止遭受其他软件的破坏
  2. 提高OS的运行效率

为了防止OS本身及关键数据(如PCB)被其他程序破坏,将处理机的执行状态分为两种:

  1. 系统态:又称管态,也称内核态,拥有执行一切指令的权限
  2. 用户态:又称目态,具有较低特权,仅能执行特定的指令

关于操作系统内核的功能我们也需要有一定的了解和认知,这里总结如下图:

image-20190701211144129

进程的创建

进程的层次结构

在操作系统中,允许一个进程创建另一个进程,被创建的进程是儿子,创建儿子的进程是父亲,而儿子有可创建新进程,这时候就有了孙子,子子孙孙无穷尽也,由此便形成了一个进程的层次结构(类似家族族谱的树形结构)。

进程之间的这种层次结构是十分重要的,比如子进程可以继承父进程的资源,父进程被撤销时一定也会撤销子进程,为了表示这种进程之间的结构关系,在PCB中设置了家族关系表项,以标明自己的父进程所有的子进程

注意:windows系统不存在进程之间的父子关系,所有进程都是平等的。

进程图

进程图没什么复杂的,就和家谱图一毛一样,主要是为了表示各个进程之间的父子关系,比如:

image-20190701212104375

引起进程创建的事件

什么情况下会进行进程的创建呢?大致分为以下四类:

image-20190701212918553

其中黄色的三类是系统内核为用户创建新进程,第四类是用户进程自己创建新进程。

进程的创建

进程创建就四步:

image-20190701213857259

进程的终止

引起进程终止的事件

引起进程终止的事件主要有三类,分别如下:

image-20190701215113517

进程终止的过程

当系统发生了要求终止进程的某事件,OS将调用进程终止原语,按照以下步骤进行进程的终止:

image-20190701215945908

进程的阻塞和唤醒

引起进程阻塞的事件

image-20190701220539548

进程阻塞的过程

正在执行的进程,如果发生了上述引起进程阻塞的事件,便会通过调用阻塞原语block将自己阻塞(即进程的阻塞是一个主动行为),然后:

  1. 立即停止执行
  2. 将进程的现行状态改为阻塞
  3. 将PCB插入阻塞队列
  4. 转调度程序,重新进行调度,将处理机分配给另一就绪执行的进程,并进行切换

进程唤醒的过程

进程唤醒是通过wakeup原语来进行实现的,过程如下:

  1. 将待唤醒的进程从阻塞队列中移出
  2. 将其PCB状态由阻塞改为就绪
  3. 将其PCB插入就绪队列中

注意:block和wakeup必须成对使用。

进程的挂起与激活

进程挂起

当进程中出现了引起进程挂起的事件后,OS将利用挂起原语suspend将指定进程挂起,执行过程如下:

  1. 检查进程的当前状态,如果处于活动就绪状态,将其置为静止就绪
  2. 如果处于活动阻塞状态,将其置为静止阻塞
  3. 为了方便用户或父进程考察该进程的运行情况,将该进程的PCB复制到某指定的内存区域
  4. 若被挂起的程序正在执行,转向调度程序重新调度

进程激活

进程的激活是通过激活原语active实现的,过程如下:将进程从外存调入内存,检查该进程的现行状态,若是静止就绪,便将之改为活动就绪;若为静止阻塞,便将之改为活动阻塞。假如采用的是抢占调度策略,则每当有静止就绪进程被激活而插入就绪队列时,便应检查是否要进行重新调度,即由调度程序将被激活的进程与当前进程两者的优先级进行比较,如果被激活进程的优先级低,就不必重新调度,否则,立即剥夺当前进程的运行,把处理机分配给刚刚被激活的进程。