2024.06.25:操作系统进程学习笔记
第6节 进程
进程是什么?进程包含什么?什么在管理进程?
6.1 进程的定义
- 进程是程序执行的一个实体
- 程序本身是没有生命周期的,不存在创建终止就绪运行等状态,它只是存在磁盘上的一些指令或者一些静态数据
- 操作系统可以让这些字节运行起来,以进程这种形式运行,让程序发挥作用。
- 只有我们让操作系统把程序调入到内存里面去执行,让CPU去处理它,它才会变得有意义
6.2 进程的基本特征(动态、并发、独立、异步)
(1)动态性:进程是程序的执行过程,(动态性)是进程的最基本特性。进程由创建而产生,由调度而执行,由撤销而消亡。所以进程具有一定的生命周期,程序只是静态的有序执行的集合
(2)并发性(重点理解)
多个进程共存于内存中,在一段时间内同时执行。所以并发也是进程里的重要特征。
输入进程在输入第一个程序后,在计算程序对该程序进程计算的同时,可由输入进程在再输入第二个程序,从而第一个进程的计算操作可与第二程序的输入操作并发执行。(单核处理器)
重点来了!!!
并发带来了更高的系统吞吐量,也带来了新的问题
- 间断性:本例的“输入-计算-打印”流程,再并发执行时,若每一环节的时间不相同,那必然会有需要等待的环节,致使在这些并发执行的进程之间,形成了相互制约的关系,导致并发进程具有“执行-暂停-执行”这种间断性的活动规律
- 失去封闭性:进程在并发执行时,是多个进程共享系统中的各种资源,因而这些资源的状态将由多个进程来改变,致使程序的运行失去了封闭性
- 不可再现性:进程在并发执行时,由于失去了封闭性,也将导致其再失去可再现性
- 一个程序在执行的时候,他执行的环境会受到另外一个程序或者进程的影响,就属于他失去了封闭性
- 如果一个程序的运行期间,它可以始终拥有这样的一个资源,或者说只有自己能更改现在这个资源的状态,这个时候我们就叫他有封闭性
(3)独立性:进程是一个能独立运行,独立获得资源,独立接受调度的基本单位。后面我们调度不同的东西去上处理机,这个对象就是进程
(4)异步性:进程都是按照异步的方式运行的,即按各自独立、不可预知的速度向前推进。异步性的本质就是你是可以有自己的节奏往前推进,不需要跟随着时钟信号去做相应的操作
6.3 机器状态(进程可以读取/更新的内容)
机器状态指的其实就是程序在进程这样的实体去运行时能读取/更新的内容
6.3.1 虚拟化技术
- 每个进程访问自己的地址空间,OS会以某种方式将它映射到机器的物理内存中。
- 对于每个进程,进程都认为自己独占了整个CPU和整个虚拟内存空间
32位程序中虚拟地址为32个bit,即程序可以访问到的地址空间最大是0xFFFF FFFF
- 为每个进程创建巨大的、私有的虚拟内存的假象
- 这种地址空间的抽象让每个程序好像拥有自己的内存,而实际上(操作系统)秘密地让多个地址空间复用物理内存(或者磁盘)
一切的功劳都在于操作系统在背后会对这个内存里面的东西进行一个对换
6.3.2 进程的地址空间(虚拟存储器技术要学会)
(1)进程的内存映像
大家可以理解为进程可以访问的内存空间,注意是可以访问,但不是都可以访问
程序调入内存运行时,就构成了进程的内存映像
对于32位的这个系统里面的每一个进程,他们的映像都是这样的一个模板
代码段
- 程序的二进制代码,代码段是只读的,可被多个进程共享,即代码段在物理内存里面只有一份,但是在不同的进程的地址空间里面,他们都可以(指向)这样的一个代码段
- 虚拟地址,需要转成主存地址
数据段
- 程序运行时加工处理的对象,包含了全局变量和静态变量
程序控制块PCB
- 放在系统区,操作系统在管理进程的时候,它会为每一个进程去设置这样的一个数据结构(PCB),PCB本身就是一个表,用来记录和这个进程相关的一些信息,他们全部都会被放到操作系统的内核区
堆
- 用来存放动态分配的变量,通过malloc函数动态地向高地址分配空间,也就是说堆是可以动态向上去增加
栈
- 用来实现函数调用,从用户空间的最大地址向低地址方向增长
操作系统内核区
- 在操作系统引导里面最终会把操作系统的内核给它放到或者说加载到主存中的某个特定区域里面,这个区域就会叫做(内核空间),而剩下叫做(用户空间)
为什么一个用户进程都访问不到的这个内核空间的地址,在进程自己的地址空间里面却出现了呢?
-
当一个用户进程想要去申请这个操作系统的服务,而操作系统提供的这些服务都在这个内核区域里面的代码,因此用户程序就会发起系统调用,让CPU陷入到内核态,从而去执行内核里面的代码。
-
但是在这个过程中,你去执行内核的代码还在这个进程的范围之内,是这个进程想要去申请内核的代码。
-
只是说这个内核的代码不属于这个进程的一部分,但是并不代表这个进程他不知道内核的代码在哪里。
对于操作系统的内核区,它里面究竟有什么,用户是看不到的。也就是对于一个进程来说,它只知道在这个地址范围内是操作系统的内核区,它并不能知道这些地址里面写了什么
进程只知道当我想要区申请操作系统的服务的时候,CPU就会去访问这样的一个地址范围,去执行内核区里面的一些代码,但是它并不知道内核区里面的代码是什么。所以这个操作系统内核区之所以可以出现在进程的地址空间里面,是因为我们前面说了进程的地址空间属于进程的一个机器状态,而机器状态指的就是它运行的过程中可以去访问到的这个区域
共享库的存储映射区
- 共享库,就是很多个进程可以去共享的一个库函数
- 共享库的存储映射区:将共享库(如动态连接库DDL)映射到进程的虚拟空间部分,使多个进程能共享同一个物理内存副本的库,节省了内存资源。
- 映射区域允许进程执行库中的代码,并访问库中的数据,就像这些代码和数据是进程自己的一部分一样
6.4 进程的状态与转换
6.3.1 进程的3种基本状态(就绪、执行、阻塞)
就绪态
- 进程已经准备好执行,已经分配到除了CPU的所有必要资源,只要获得CPU就可以立即执行。若有多个就绪态进程,通常会将其排成队列,称就绪队列
进程已经准备好,只要获得CPU就可以立即执行
执行态
- 进程获得CPU后,程序“正在执行”这一状。对任何一个时刻而言,在单处理机系统中,只有一个进程处于执行状态,在多处理机系统中,可能有多个进程处于执行状态
进程获得CPU后,程序“正在执行”这一状态
阻塞态
- 正在执行的进程由于发生某事件(如IO请求、申请缓冲区失败等)暂时无法执行,即进程的执行受到了阻塞。这时会引起系统调度,OS把处理机分配给另一个就绪进程,让受阻进程处于暂停状态,这种暂停状态称为阻塞状态,处于阻塞状态的进程排成队列,叫阻塞队列
正在执行的进程由于发生某事件(如io请求、申请缓冲区失败等)暂时无法执行,即进程的执行受到了阻塞
6.3.2 创建状态和终止状态
(1)创建状态
若进程所必需的资源尚不能得到满足(如内存不足),创建工作尚未完成,此时称为创建状态
创建状态是一个复杂的过程,一般通过多个步骤才能完成
- 由进程申请一个空白的PCB,并且向PCB中填写用于控制和管理进程的信息
- 为该进程分配运行时所需的资源
- 把该进程状态转换为就绪态,插入就绪队列之间
引入一个linux系统里面用于创建进程的两个系统调用作为知识的补充
两个创建进程相关的系统调用
- fork():父进程调用fork()会拷贝出一个子进程,它拥有自己的地址空间、寄存器、PC等,fork()返回给父进程子进程的PID(内部标识符)
- exec():从可执行程序中加载代码和静态数据,并用它覆写自己的代码段,堆栈等其他内存空间也会被重新初始化
- 先fork(),再exec(),就拥有了新的进程
(2)终止状态
进程的终止也要通过两个步骤
- 等待OS进行善后处理
- 将进程PCB清零之后,将PCB空间返还给操作系统
- 一个进程在被终止之前是可以有很多状态的(细品)
当一个进程到达了自然结束点,或者出现了无法克服的错误,或被操作系统所终止
或被其他有终止权的进程终止时,它就会进入终止状态。进入终止状态的进程不会被执行,但是操作系统中会保留一个记录,保存状态码和一些计时统计数据供其它进程收集
其他进程完成信息提取后,系统就会删除该进程,PCB清零并将空白PCB还给OS
6.3.3 挂起操作和进程状态的转换
挂起在某些系统里面,指的就是把一个进程从内存调出,然后放到外存里面去,等它激活的时候,就再做相反的操作。也有的系统,挂起并非把它移出内存,它可能还在内存里面,只是处于一个暂停的状态
在很多系统中,除去就绪、执行、阻塞以外还引入了“挂起”操作,与之对应的是“激活”操作,有以下几种状态转换:
- (活动就绪)到(静止就绪):进程处于未被挂起的就绪状态,称为(活动就绪状态),此时进程可以接受调度。当用挂起原语Suspend将进程挂起后,该进程的状态转换为(静止就绪状态),并且不会再被调度执行
- (活动阻塞)到(静止阻塞):进程处于未被挂起的阻塞态,称(活动阻塞态),使用挂起原语Suspend将进程挂起后,进程的状态转换成了(静止阻塞状态),这样状态的进程在所期待的事件发生后,从静止阻塞状态转变为静止就绪状态
- (静止就绪)到(活动就绪):静止就绪的进程,使用激活原语Active将其激活,则该进程的状态会转换为就绪状态,得到CPU资源就可执行
- (静止阻塞)到(活动阻塞):静止阻塞的进程,使用激活原语Active将其激活,该进程的状态会转换为活动阻塞状态
比起之前的5个状态转换,需要额外考虑以下情况:
- (NULL)到(创建): 一个新进程产生时处于创建状态
- (创建)到(活动继续):在当前系统性能和内存容量允许的情况下,完成进程创建必要操作后,系统会将进程状态转换为活动就绪状态
- (创建)到(静止就绪):当前的系统资源状况和性能要求不允许的情况下,系统不会分配给新建进程所需资源(主要是内存),还会将进程转换为静止就绪状态。进程放在外存不参与调度,创建工作尚未完成
- (执行)到(终止):一个进程已完成任务,或出现了无法克服的错误,或被操作系统或其它进程所终止时,将进程状态转换为终止状态
6.5 进程管理中的数据结构
6.5.1 PCB进程控制块定义
为了便于管理和使用计算机中的各类资源,OS将它们抽象为相应的各种数据结构,并提供一组对资源进行操作的命令
为了便于系统描述和管理进程,OS为每个进程定义了一个数据结构PCB(进程控制块),PCB用于记录OS所需的、用于描述进程当前的情况以及管理进程运行状态的全部信息,是OS最重要的记录型数据结构
6.5.2 PCB进程控制块具体作用
- 作为独立运行基本单位的标志
- 实现间断性运行方式
- 提供进程管理所需要的信息
- 提供进程调度所需信息
- 实现与其他进程的同步和通信
6.5.3 PCB进程控制块中的信息(背下来!)
(1)进程标识符
- 外部标识符:为方便用户对进程的访问,为每个进程设置一个外部标识符。通常由字母和数字组成。为了描述进程家族关系,还应设置父进程标识符和子进程标识符。此外还可设置用户标识符,指示拥有该进程的用户
- 内部标识符PID:为方便系统对进程的使用,在操作系统中为进程设置了内部标识符,赋予每个进程唯一一个数字标识符,通常是一个进程序号,数字
(2)处理机状态
处理机的状态信息,也称处理机CPU的上下文,主要是由处理机的各种寄存器中的内容组成,包括:
- 通用寄存器(用户可视寄存器):可被用户程序访问,用于暂存信息
- 指令计数器PC:其中存放了要访问下一条指令的地址
- 程序状态字寄存器PSW:每个用户进程都有与之相关的系统栈,用于存放进程和系统的调用地址。栈指针指向该栈栈顶,处理机执行状态时,正在处理的许多信息也是放在寄存器中的。进程被切换时,处理机状态信息都必须保存在相应的PCB中
- 堆栈指针寄存器SP:指向用户自己堆栈的指针和指向内核栈的指针
(3)进程调度信息
因为操作系统要对进程进行调度,所以需要了解以下信息:
- 进程状态:指明进程当前的状态(阻塞、就绪、运行),作为进程调度、对换的依据
- 进程优先级:描述进程使用处理机的优先级别(用一个整数表示),优先级高的优先获得处理机
- 进程调度所需的其它信息:部分进程调度算法需要知道进程已等待CPU时间总和、进程已执行时间总和等
- 事件:进程由执行状态转换为阻塞状态所等待发生的事件(阻塞的原因)
(4)进程控制信息
指用于进程控制所必须的信息
- 程序和数据的地址:即程序和数据的内存或外存起始地址,便于该进程执行时能从PCB中快速找到程序和数据
- 进程同步和通信机制:比如消息队列指针、信号量等,它们可能会全部或部分放在PCB中
- 资源清单:列出了该进程在运行期间所需的全部资源(除CPU外)
- 链接指针:给出本进程所在队列中的下一个进程的PCB起始地址
6.5.4 PCB的组织方式
(1)线性方式
所有PCB组织在一张线性表中,起始地址放在内存的一个专用区域中,这样的方式简单,开销小,但每次查找都需要扫描整张表,适合进程不多的系统
(2)链接方式
将具有相同状态的进程PCB分别链接成一个队列,就绪队列可按照优先级排序,阻塞队列可以根据阻塞原因分成多个阻塞队列
(3)索引方式
操作系统根据进程状态的不同,建立几张索引表,把各索引表在内存中起始位置记录在内存的专用单元中。每个索引表,记录具有相应状态的某个PCB在PCB表中的地址
6.6 进程的控制
6.6.1 进程的创建
操作系统中允许一个进程创建另一个进程,通常把创建新进程的进程称为父进程,被创建的称为子进程。子进程可以继续创建其自己的子进程(即父进程的孙进程)。
在UNIX系统中,进程与其子孙进程可以共同组成一个进程家族(进程组)
- 子进程可以继承父进程所拥有的资源(打开的文件,分配的缓冲区)。当子进程被撤销时,应将从父进程那里获得的资源归还给父进程
- 在撤销父进程时,也必须同时撤销所有的子进程
在windows系统中不存在任何进程层次结构的概念,所有进程有相同的地位。一个进程创建了另外一个进城后,创建进程获得了一个句柄,作用相当于令牌,可控制被创建进程,同时句柄可以进行传递。
因此进程间关系不是层次关系,而是控制与被控制的简单关系
(1)引起进程创建的事件
- 用户登录:分时系统中,用户在终端输入登录命令后,若登录成功,则系统会为该用户创建一个进程,并插入就绪队列
- 作业调度:多道批处理系统中,作业调度程序按一定的算法调度到某个队列中
- 提供服务:运行中的用户程序提出某种请求后,系统专门创建一个进程为用户提供所需的服务(如打印文件创建打印进程)
- 应用请求:上面三种情况是操作系统内核为用户创建新进程;针对应用请求,则是用户进程自己创建新进程,进程间并发执行完成任务
(2)进程创建的步骤
- 申请空白的PCB,为新进程申请一个唯一的数字标识符
- 为新进程分配其运行所需的资源,包括各种物理和逻辑资源,如内存、文件、IO设备、CPU时间
- 初始化PCB
-
- 初始化标志信息,将系统分配的标识符和父进程标识符填入新PCB;
-
- 初始化处理机状态信息,使程序计数器指向程序的入口地址,使栈指针指向栈顶
-
- 初始化处理机控制信息,将进程的状态设置为就绪状态或静止就绪状态,通常还须将
其设置为最低优先级’
- 初始化处理机控制信息,将进程的状态设置为就绪状态或静止就绪状态,通常还须将
- 如果进程就绪队列能够接纳新进程,就将新进程插入就绪队列
补充
进程创建新进程时,有两种执行的可能:
- 父进程与子进程并发执行
- 父进程等待,直到其某个或全部子进程
新进程的内存映像也有两种可能:
- 子进程是父进程的复制品(子进程与父进程具有相同程序和步骤)
- 子进程加载另一个新程序
6.6.2 进程的终止
(1)引起进程终止的操作
- 正常结束:进程的任务已完成,准备退出运行。任何系统中都应有⼀个⽤于表示进程已经运行完成的指示。通常会在程序的最后安排⼀条指令,用于向OS表示运行已结束。程序到该运行指令时,会产生⼀个中断通知OS本进程运行完毕
- 异常结束
- 外界干预
(2)进程终止的过程
发生了要求终止进程的事件后,操作系统会调用进程终止原语,按照一定步骤终止制定进程。
- 根据被终止进程的标识符,从PCB集合中找到该进程PCB,读出该进程状态
- 若被终止进程处于执行状态,立刻终止执行
- 若该进程还有子孙进程,还应终止其所有子孙进程,以防它们成为不可控进程
- 将被终止进程拥有的全部资源归还给父进程或系统
- 将被终止进程的PCB从所在队列中移除
6.6.3 进程的阻塞与唤醒
(1)引起进程阻塞的事件
- 向系统请求共享资源失败
- 等待某种操作的完成
- 新数据尚未到达
- 等待新任务的到达
(2)进程阻塞的过程
正在执行的进程,发生引起阻塞的事件,就会调用阻塞原语block将自己阻塞,故阻塞是进程自身的主动行为,进入block阶段后,由于该进程还处在执行状态,OS停止执行该进程,PCB中改为阻塞态,将PCB插入阻塞队列,再转至调度程序进行重新调度操作
(3)进程唤醒的过程
被阻塞进程所期待的事件发生时,就会调用唤醒原语wakeup以将等待该事件的进程唤醒
阻塞原语和唤醒原语是一对作用相反的原语,使用它们时必须成对使用
wakeup的执行过程
- 将被阻塞的过程从等待该事件的阻塞队列中移出,将其PCB中的现行状态改为就绪
- 将该PCB插入就绪队列
6.7 进程通信
进程通信有低级和高级之分
- 低级进程通信:效率低、通信对用户不透明
- 高级进程通信:高效传输大量数据、使用方便、对用户透明
6.7.1 共享存储器系统
共享存储器系统中,相互通信的进程共享某些数据结构或存储区,进程之间通过这些空间进行通信
(1)基于共享数据结构的通信方式
要求各进程共享某些数据结构完成信息交换,操作系统仅提供共享存储器,由程序员负责对共享数据结构进行设置和对进程间同步进行处理。效率低下,属于低级进程通信
(2)基于共享存储区的通信方式
为了传送大量数据,在内存中划出一块共享存储区,各进程可通过对该区域的读写交换信息、通信,数据的形式、位置甚至访问均由进程控制,而非操作系统,属于高级通信
6.7.2 管道通信系统
管道指用于连接一个读进程以实现它们之间通信的一个共享文件,也叫pipe文件
管道必须提供三方面的协调能力
- 互斥:当一个进程正在对管道执行读/写操作时,其它进程必须等待
- 同步:当写进程把一定数量的数据写入管道后,等待,直到读进程取走数据后,再把它唤醒;读进程读一空管道时,也应等待
- 确定对方是否存在,对方已存在时才能进行通信
6.7.3 消息传递系统
消息传递系统中,进程不必借助任何共享数据结构或存储区,而是会以(格式化的消息)为单位,将通信的数据封装在消息中
- 直接通信方式:发送进程利用操作系统所提供的发送原语,直接把消息发送给目标进程
- 间接通信方式:发送进程和接受进程都通过共享中间实体(信箱)进行消息的发送和接收