进程的概念、状态、通信等
预备知识
前驱图

程序顺序执行的特征
-
顺序性
- 顺序执行
-
封闭性
- 独占资源
-
可再现性
- 只要程序执行环境和初始条件相同,重复执行时结果都相同
程序并发执行的特征
-
间断性
-
失去封闭性
-
不可再现性
因为程序并发执行时,是多个程序共享系统中的各种资源,因而这些资源的状态是由多个程序来改变,致使程序的运行失去了封闭性。而程序一旦失去了封闭性也会导致其再失去可再现性。
- 执行结果与并发程序的执行速度相关
进程的概念
非正式地说,进程是执行的程序。
进程不只是程序代码,程序代码又称为文本段或代码段。
进程还包括当前活动(程序计数器的值、处理器寄存器的内容)。
通常还包括进程堆栈(临时数据)、数据段(全部变量)。
还可能包括堆(进程运行时动态分配的内存)。
进程的特征
-
动态性
- 进程有生命周期,最基本特征。
-
并发性
- 可并发执行;引入进程的目的是为
了使其进程实体能和其他进程实体并发执行
- 可并发执行;引入进程的目的是为
-
独立性
- 进程实体是一个能独立运行、独
立获得资源和独立接受调度的基本单位
- 进程实体是一个能独立运行、独
-
制约性
- 进程间对资源的争用而相互制约
-
异步性
- 进程按照各自独立的、不可预知
的速度向前推进
- 进程按照各自独立的、不可预知
-
结构特征
- 进程=程序+数据+PCB
进程和程序的比较
进程是程序的一次运行过程,是一个动态实体,而程序是一个指令的集合,是静态实体。
进程具有生命周期,具有创建、执行和撤销的过程,而程序一旦创建,可以永远存在 。
进程实体由程序段、数据段及进程控制块组成。
进程与程序之间不存在一一对应的关系,不同的进程可以对应相同的程序,一个进程中还可以同时调用多个程序。
进程实体是一个能独立运行的基本单位,可独立获得资源和独立调度;而程序不能作为独立的单位参加运行。
进程可按异步方式运行,程序不是运行实体,所以不可以异步执行。
进程的状态
就绪、运行、等待是三个基本状态。
- 提交状态
- 后备状态
- 就绪状态
- 运行状态
- 等待状态
- 结束状态

进程的挂起/解挂
-
设置挂起/解挂的原因
用户需要:中间结果与预期不符。
操作系统需要:系统某些功能故障。
系统负荷过重 。
父进程请求:修改或协调子进程 。
对换的需要。

进程控制块(PCB)
PCB是用以记录与进程相关信息的主存区,是进程存在的唯一标志
-
PCB构成
-
进程状态
-
进程标识信息
-
进程本身信息
- 进程标识
-
家族信息
- 父进程信息
- 子进程信息
-
-
程序计数器
-
CPU寄存器
-
CPU调度信息
- 进程优先级
- 调度队列的指针
-
内存管理信息
- 基地址
- 界限寄存器的值
- 页表或段表
-
记账信息
- CPU时间
- 实际使用时间
- 时间期限
-
I/O状态信息
- 分配给进程的I/O设备列表
- 打开文件列表
-
-
PCB的组织方式
-
线性方式
系统中所有PCB都组织在一张线性表中,表的首地址存放在内存专用区。
-
链式方式
具有相同状态进程的PCB分别通过PCB中的链接字链接成一个队列。

-
索引方式
系统根据所有进程状态的不同,建立几张索引表,并把索引表的首地址记录在内存的专用单元中。

-
-
Linux PCB的例子

进程切换/上下文切换
切换CPU到另一个进程需要保存当前进程状态和恢复另一个进程的状态,内核会将旧进程状态保存在PCB中,并加载调度新的进程。
上下文切换的时间是纯粹的开销。
有的处理器提供多个寄存器组,上下文切换只需简单改变当前寄存器组的指针(如果活动进程数量超过寄存器组的组数,系统仍要在寄存器和内存之间复制数据)。

进程的创建
进程图
进程图(有向树)与前趋图(有向无环图)的2个区别:
1、表示的含义不同;
2、执行时处理不同:可并发执行
进程创建原语Creat()
- 申请空白PCB
- 为新进程分配资源
- 初始化PCB
- 新进程插入就绪队列
父进程创建子进程
当一个进程创建子进程时,子进程会需要一定的资源。子进程可以直接从操作系统那获得资源,也可以只从父进程那里获得资源子集。父进程可能要在子进程之间分配资源或共享资源。限制父进程只能使用父进程的资源,可以防止创建过多进程,导致系统超载。
-
父与子进程的执行可能
- 父进程和子进程并发执行
- 父进程等待,直到某个或某些子进程执行完毕
-
新进程的地址空间的情况
- 子进程完全复制父进程,拥有同样的程序和数据
- 子进程加载另一个新程序
Unix举例
-
fork()
通过系统调用fork()创建新进程,新进程的地址空间复制了原来进程的地址空间。子进程和父进程都继续执行fork()调用后的指令。
但对于父进程,fork()返回子进程的进程标识。
对于子进程,fork()返回0。 -
exec()
在调用fork()后,可以有个进程调用exec(),用新程序取代进程的地址空间(加载二进制文件到内存),并开始执行。
-
wait()
父进程创建子进程后,如果无事可做,就调用wait()把自己移除就绪队列,直到子进程结束,wait()返回(可以获得子进程的标识符、退出状态等信息),父进程从wait()的下一条指令开始继续执行。
进程的终止
级联终止
如果一个进程终止,那么它的所有子进程也相应终止,称为级联终止。
僵尸进程
当一个进程终止时,操作系统会释放它的资源,但是位与进程表中的条目还在,直到它的父进程调用wait()。
因为进程表中包含了进程的退出状态,当进程已经终止,但它的父进程还没有调用wait()时,这样的进程称为僵尸进程。
一旦父进程调用wait(),僵尸进程的进程标识符和进程表中的条目就会被释放。
孤儿进程
如果父进程没有调用wait()就终止,它的子进程称为孤儿进程。
Linux和Unix的做法是,将init进程作为孤儿进程的父进程。init进程定期调用wait(),以便收集孤儿进程的退出状态,释放孤儿进程的标识符和进程表条目。
进程间通信
操作系统内的并发执行程序可以是独立的,也可以是协作的,若是协作的,那么就需要有一种进程间通信(IPC)的机制。
生产者-消费者问题
-
方法之一:采用共享内存
-
缓冲区
-
无界缓冲区
生产者总是可以产生新的项,而消费者可能等待新的项。
-
有界缓冲区
如果缓冲区空,消费者必须等待;如果缓冲区满,生产者必须等待。
- 循环数组和两个逻辑指针,IN指向下一个空位,out指向第一个满位
- in=out时缓冲区为空
- (in+1)%BUFFER_SIZE=out时缓冲区满
- 缓冲区最大容量为BUFFER_SIZE-1
-
-
进程通信的类型
消息传递对于较小数量的数据交换很有用,因为无需避免冲突。对于分布式系统,消息传递也比共享内存更易实现。
共享内存可能快于消息传递,因为消息传递的实现经常采用系统调用,需要消耗更多时间使内核介入。共享内存仅在建立共享内存区域使需要系统调用,建立后所有访问都可作为常规内存访问,无需借助内核。
-
共享存储器
共享内存会有高速缓存一致性问题,是由于共享数据在多个高速缓存之间迁移引起的。
一片共享内存区域驻留在创建共享内存段的进程的地址空间内,希望使用这个共享内存区域进行通信的进程需要把它也附加到自己的地址空间。
数据的类型或位置取决于进程而不受控于操作系统。
进程负责确保不向同一位置同时写入数据。-
共享数据结构
信息交换的格式、类型一定;
进程通信由程序员完成,效率低; -
共享存储区
-
-
消息传递
由操作系统提供机制,利用系统提供的通信原语,以消息或报文为单位进行信息交换。
-
命名
需要通信的进程应有一个方法,以便互相引用。
-
直接通信
-
对称寻址
- send(P,message):向进程P发送message
- receive(Q,message):从进程Q接收message
-
非对称寻址
- send(P,message):向进程P发送message
- receive(id, message):从任何进程,接收 message,这里变量 id 被设置成与其通信进程的名称。
-
-
间接通信
-
通过信箱发送或接收消息
每个信箱有唯一的标识符
-
send()/receive()
- send(A,message):向信箱A发送message
- receive(A,message):从信箱A接收message
-
信箱分类
- 私有信箱
- 公用信箱
- 共享信箱
-
-
-
-
同步
实现send()/receive()原语有不同的设计方案。
不同组合的send()/receive()都有可能。-
阻塞/同步
- 阻塞式发送
- 阻塞式接收
-
非阻塞/异步
- 非阻塞式发送
- 非阻塞式接收
-
-
缓存
不论是直接还是间接的通信,通信进程交换的消息总是驻留在临时队列中。
-
无缓冲消息系统
-
零容量
链路中不能有任何消息处于等待。发送者应阻塞,直到接收者收到消息。
-
-
自动缓冲消息系统
- 有限容量
- 无限容量
-
-
-
管道通信
用于连接一个读进程和一个写进程,以实现它们之间
通信的共享文件,又称为Pipe文件。-
普通管道
- 单向:只能有一个进程作为这个管道的发送端
- 同步:管道满时,发送进程等待
- 互斥:同一时刻,只能有一个进程对管道操作
-
命名管道
-

浙公网安备 33010602011771号