进程
进程的概念
程序:是静态的,就是个存放在磁盘里的可执行文件,就是一系列的指令集合
进程( Process ):是动态的,是程序的一次执行过程,同一个程序多次执行会对应多个进程
进程的组成
一个进程实体(进程映像)由 PCB 、程序段、数据段组成:进程是动态的,进程实体(进程映像)是静态的。
程序段、数据段、 PCB 三部分组成了进程实体(进程映像)
引入进程实体的概念后,可把进程定义为:
进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位
注意:PCB是进程存在的唯一标志!
进程控制块( PCB )
当进程被创建时,操作系统会为该进程分配一个唯一的、不重复的“身份证号”-- PID (Process ID ,进程 ID )
包括 PID 、进程状态、进程优先级、进程控制信息、进程资源信息等将保存在一个称为 PCB ( Process Control Block ) 的数据结构中
所有操作系统需要使用的,用于管理进程的信息,都保存在 PCB 中
PCB 是进程存在的唯一标志,当进程被创建时,操作系统为其创建 PCB ,当进程结束时,会回收其 PCB
程序段
PCB 部分是操作系统使用的,用于管理进程的信息,而程序段和数据段是进程使用的
程序的运行过程:
源代码编译完成的可执行文件存在硬盘中 ( Windows 中为 .exe 后缀的文件)
运行前将可执行文件加载到内存中,其中将开辟三个空间分别是 PCB 、程序段和数据段
程序段包含所有的指令,数据段包含运行中所需要的数据(包括源代码中显式声明的变量),操作系统则会在 PCB 中创建对应的 PID 等信息并初始化操作系统会为进程分配 CPU 时间片,进程会按照时间片的大小,轮流使用 CPU 执行指令
……
进程的特征
程序是静态的,进程是动态的,相比于程序,进程拥有以下特征:
- 动态性
进程是程序的一次执行过程,是动态地产生、变化和消亡的
动态性是进程最基本的特征
- 并发性
内存中有多个进程实体,各进程可并发执行
- 独立性
进程是能独立运行、独立获得资源、独立接受调度的基本单位
- 异步性
各进程按各自独立的、不可预知的速度向前推进操作系统要提供“进程同步机制”来解决异步问题
- 结构性
每个进程都会配置一个 PCB ,结构上看,进程由程序段、数据段、 PCB 组成
上述特征仅要求理解,不需要逐字记忆
进程的状态
进程的状态分为三种基本状态:
- 阻塞态
- 就绪态
- 运行态
和其他两种状态
- 创建态
- 终止态
进程的 PCB 中,会有一个变量 state 来表示进程的当前状态。如: 1 表示创建态、 2 表示就绪态、 3 表示运行态……
进程的整个生命周期中,大部分时间都处于三种基本状态
单 CPU 情况下,同一时刻只会有一个进程处于运行态,多核 CPU 情况下,可能有多个进程处于运行态
创建态 ( New )
进程正在被创建时,它的状态是“创建态”,在这个阶段操作系统会为进程分配资源、初始化 PCB
就绪态 ( Ready )
当进程创建完成后,便进入“就绪态”处于就绪态的进程已经具备运行条件,但由于没有空闲 CPU ,就暂时不能运行
运行态 ( Running )
如果一个进程此时在 CPU 上运行,那么这个进程处于“运行态”。CPU会执行该进程对应的程序(执行指令序列)
系统中可能会有很多个进程都处于就绪态,当 CPU 空闲时,操作系统就会选择一个就绪进程,让它上处理机运行
阻塞态 ( Blocked )
阻塞态又称等待态( Waiting )
在进程运行的过程中,可能会请求等待某个事件的发生(如等待某种系统资源的分配,或者等待其他进程的响应),在这个事件发生之前,进程无法继续往下执行,此时操作系统会让这个进程下 CPU ,并让它进入“阻塞态”
当 CPU 空闲时,又会选择另一个“就绪态”进程上 CPU 运行
当等待的事件发生时,进程从“阻塞态”回到“就绪态”
终止态 ( Terminated )
终止态又称结束态
一个进程可以执行 exit 系统调用,请求操作系统终止该进程此时该进程会进入“终止态”,操作系统会让该进程下 CPU ,并回收内存空间等资源,最后还要回收该进程的 PCB
当终止进程的工作完成之后,这个进程就彻底消失了
进程状态的转换
阻塞态→就绪态不是进程自身能控制的,是一种被动行为
运行态→阻塞态是一种进程自身做出的主动行为
注意
不能由阻塞态直接转换为运行态,也不能由就绪态直接转换为阻塞态(因为进入阻塞态是进程主动请求的,必然需要进程在运行时才能发出这种请求)
进程的组织
为了对同一个状态下的各个进程进行统一的管理,操作系统会将各个进程的 PCB 组织起来
进程的组织方式主要分为两种:
- 链式方式
- 索引方式
链接方式(链式方式)
采用链接方式的进程组织方式,操作系统会维护几个队列,每个队列对应一个状态,如就绪队列、阻塞队列等
执行指针对应处于运行态的进程(单 CPU 计算机中,同一时刻只会有一个进程处于运行态)
就绪队列指针指向当前处于就绪态的进程,通常会把优先级高的进程放在队头
很多操作系统还会根据阻塞原因不同,再分为多个阻塞队列,比如:等待打印机的阻塞队列、等待磁盘的阻塞队列等
索引方式
采用索引方式的进程组织方式,操作系统会维护一个索引表,每个索引项对应一个进程的 PCB
执行指针仍然只指向当前处于运行态的进程
就绪表指针指向当前处于就绪态的进程,通常会把优先级高的进程放在表头
简要了解就行,索引方式的进程组织方式在实际中用的比较少,大部分操作系统采用链式方式进行组织
进程控制
什么是进程控制?
进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能
简化理解:反正进程控制就是要实现进程状态转换
如何实现进程控制
需使用“原语”实现
原语的执行具有原子性,即执行过程只能一气呵成,期间不允许被中断
原语需要一气呵成的原因就是为了避免进程在状态转换的执行过程中被中断,导致进程的状态与所在的队列不一致(根据上面进程组织的方式,不同状态的进程会被挂载到不同的队列中)
可以用“关中断指令”和“开中断指令”这两个特权指令实现原子性
正常情况: CPU 每执行完一条指令都会例行检查是否有中断信号需要处理,如果有则暂停运行当前这段程序,转而执行相应的中断处理程序
CPU 执行了关中断指令之后,就不再例行检查中断信号,直到执行开中断指令之后才会恢复检查
这样,关中断、开中断之间的这些指令序列就是不可被中断的,这就实现了“原子性”,而期间收到的中断信号将会在开中断指令执行之后依次执行
进程的创建
创建原语
- 申请空白 PCB
- 为新进程分配资源
- 初始化 PCB
- 将 PCB 插入就绪队列(创建态→就绪态)
引起进程创建的事件
- 用户登录——分时系统中,用户登录成功,系统会建立为其建立一个新的进程
- 作业调度——多道批处理系统中,有新的作业放入内存时,会为其建立一个新的进程
- 提供服务——用户向操作系统提出某些请求时,会新建一个进程处理该请求
- 应用请求——由用户进程主动请求创建一个子进程
进程的终止
撤销(终止)原语
- 从 PCB 集合中找到终止进程的 PCB (就绪态 / 阻塞态 / 运行态→终止态)
- 若进程正在运行,立即剥夺 CPU ,将 CPU 分配给其他进程
- 终止其所有子进程(进程之间的关系是树形结构,终止进程时,需要终止其所有子进程)
- 将该进程拥有的所有资源归还给父进程或操作系统
- 删除 PCB (终止态→无)
引起进程终止的事件
- 正常结束——进程请求终止:使用 exit 系统调用
- 异常结束——整数除以 0 、非法使用特权指令:操作系统会强行终止该进程
- 外界干频—— Ctrl + Alt + delete ,用户选择杀掉进程
进程的阻塞
阻塞原语
- 找到要阻塞的进程对应的 PCB
- 保护进程运行现场,将 PCB 状态信息设置为“阻塞态”,暂时停止进程运行
- 将 PCB 插入相应事件的等待队列(就绪态→阻塞态)
引起进程阻塞的事件
- 需要等待系统分配某种资源
- 需要等待相互合作的其他进程完成工作
进程的唤醒
唤醒原语
- 在事件等待队列中找到要唤醒的进程对应的 PCB
- 将 PCB 从等待队列移除,设置进程为就绪态
- 将 PCB 插入就绪队列,等待被调度(阻塞态→就绪态)
引起进程唤醒的事件
- 等待的事件发生
注意
阻塞原语唤醒原语必须成对使用,因何事阻塞,就应由何事唤醒
进程的切换
切换原语
- 将当前进程的运行环境信息(进程上下文包含 GPR、IR、PSW、PC 等寄存器内的必要信息)存入 PCB
- 将当前进程的 PCB 移入相应队列
- 选择另一个进程执行,并更新其 PCB
- 根据 PCB 恢复新进程所需的运行环境(运行态→就绪态;就绪态→运行态)
引起进程切换的事件
- 当前进程时间片到
- 有更高优先级的进程到达
- 当前进程主动阻塞
- 当前进程终止
注意
运行环境信息在运行时主要存在于 CPU 的各个寄存器中,其包含:
- 通用寄存器(GPR ,存放必要数据)
- 指令寄存器(IR ,存放当前正在执行的指令)
- 程序状态寄存器(PSW ,存放程序运行时的状态信息)
- 程序计数器(PC ,存放下一条指令的地址)
- 栈指针
- 基址指针
- 标志寄存器
……
提示
无论哪个进程控制原语,要做的无非三类事情:
- 更新进程 PCB 中的信息(修改进程状态( state ),保存 / 恢复运行环境)
- 将 PCB 插入合适的队列
- 分配 / 回收资源
进程间的通信
进程间通信( IPC , Inter-Process Communication )是指两个进程之间产生数据交互
进程是分配系统资源的单位(包括内存地址空间、 CPU 时间等),因此各进程拥有的内存地址空间相互独立
为了保证安全,一个进程不能直接访问另一个进程的地址空间
进程间通信主要采用三种方式:
- 共享存储
- 消息传递
- 管道通信
共享存储
通过“增加页表项 / 段表项”即可将同一片共享内存区映射到各个进程的地址空间中
Linux 中,如何实现共享内存:
int shm_open(xxx); // 通过 shm_open 系统调用,申请一片共享内存区
void * mmap(xxx); // 通过 mmap 系统调用,将共享内存区映射到进程的地址空间为避免出错,各个进程对共享空间的访问应该是互斥的
各个进程可使用操作系统内核提供的同步互斥工具(如 P 、 V 操作)来实现对共享空间的访问互斥
共享存储可以进一步划分为:
基于存储区的共享:操作系统在内存中划出一块共享存储区,数据的形式、存放位置都由通信进程控制,而不是操作系统。这种共享方式速度很快,是一种高级通信方式
基于数据结构的共享:比如共享空间里只能放一个长度为 10 的数组。这种共享方式速度慢、限制多,是一种低级通信方式
消息传递
进程间的数据交换以格式化的消息( Message )为单位。进程通过操作系统提供的“发送消息”和“接收消息”两个原语进行数据交换。
格式化的消息
格式化的消息包含:
- 消息头:发送进程 ID 、接受进程 ID 、消息长度等格式化的信息
- 消息体:包含实际要传递的数据
消息传递分为两种方式:
- 直接通信方式
消息发送进程要指明接收进程的 ID
具体过程:
假设有两个进程 P 、 Q , P 要发送消息给 Q ,则:
- P 构造消息数据结构,使用发送原语,指明接收进程为 Q
- 操作系统接收到消息,将该消息挂载到操作系统内核的 P 进程的 PCB 中的消息队列上
- Q 可以使用接收原语,指明发送进程 P
- 操作系统将消息从 P 进程的消息队列中取出,复制到 Q 进程对应的内存区域
- 间接通信方式
通过“信箱”间接地通信,因此又称“信箱通信方式”
具体过程:
仍假设有两个进程 P 、 Q , P 要发送消息给 Q ,则:
- P 可以向操作系统申请数个信箱 A 、 B ,并在构造消息后,使用发送原语,指明接收信箱 A
- Q 使用接收原语,指明接收信箱 A 中的消息
提示
多个进程可以往同一个信箱中发送消息,也可以从同一个信箱中接收消息
管道通信
“管道”是一个特殊的共享文件,又名 pipe 文件。其实就是在内存中开辟一个大小固定的内存缓冲区
两个进程使用一个管道,并且是单向的,管道本质上是一个循环队列,消息只允许先进先出,依次读取
管道通信和共享存储的区别
| 区分点 | 管道通信 | 共享存储 |
|---|---|---|
| 读写数据 | 写方只允许按顺序写入,读方只能按顺序读取 | 读写方可以随机读写 |
管道通信的要点:
- 管道只能采用半双工通信,某一时间段内只能实现单向的传输。如果要实现双向同时通信,则需要设置两个管道
- 各进程要互斥地访问管道(由操作系统实现)
- 当管道写满时,写进程将阻塞,直到读进程将管道中的数据取走,即可唤醒写进程
- 当管道读空时,读进程将阻塞,直到写进程往管道中写入数据,即可唤醒读进程
- 管道中的数据一旦被读出,就彻底消失。因此,当多个进程读同一个管道时,可能会错乱。对此,通常有两种解决方案:
① 一个管道允许多个写进程,一个读进程( 2014 年 408 真题高教社官方答案);(以此为准)
② 允许有多个写进程,多个读进程,但系统会让各个读进程轮流从管道中读数据( Linux 方案 )
管道随时可读可写,不需要填满后才能被读取
更新日志
e023d-于13cfe-于86223-于
