前趋图和程序执行
前趋图
有向无循环图,记为DAG(Directed Acyclic Graph),用于描述进程之间执行的前后关系
- 节点表示:一条语句、一个程序段、一个进程
- 结点间的有向边则用于表示两个结点之间存在的偏序(Partial Order)或前趋关系(Precedence Relation)
初始结点:无前趋的节点
终止结点:无后继的节点
重量表示该结点所含有的程序量或结点的执行时间。
程序执行
程序顺序执行
特征
- 顺序性:处理机的操作严格按照程序所规定的顺序执行
- 封闭性:程序运行时独占全机资源
- 可再现性:只要程序执行时的环境和初始条件相同,都将获得相同的结果
保证程序的正确性
程序并发执行
分批处理
实现减耦合,减小依赖,实现并发的可行
特征
- 间断性: 执行–暂停–执行
- 失去封闭性:资源的状态由多个程序改变
- 不可再现性: 程序运行速度不同,导致结果不同
进程的描述
定义
引入原因:
- 程序不能并发执行
- 对并发执行的程序加以控制和描述
典型定义:
- 进程是程序的一次执行(过程)
- 进程是一个程序及其数据在处理及上顺序执行时所发生的活动(动态性)
- 进程时具有独立功能的程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位
(有限环境下,引入线程后调度由线程控制)
结构特征
- 为使程序(含数据)能独立运行,应为之配置一进程控制块
- 利用PCB(进程控制块)描述进程的基本情况和活动进程,进而控制和管理进程
- 由程序段、数据段及进程控制块三部分构成,总称“进程映像”
- 创建和撤销进程,实质上都是对PCB的操作
动态性
- 最基本特征。
- 由创建而产生,由调度而执行,由撤销而消亡
- 进程实体有一定的生命周期
- 程序是指令集,本身不是运动的,是静态的(程序是剧本,进程是程序的一次执行)
并发性
多个进程实体存在于内存中,并且在一段时间内同时运行
独立性
进程实体是一个能独立运行、独立分配资源和独立接受调度的基本单位
异步性
进程按各自独立的、不可预知的速度向前推进
基本状态及转换
进程执行要由调度程序调度才能占用CPU执行
两状态进程模型
队列(就绪队列)中存放not running 的进程
三种基本状态
- 就绪状态:只差CPU就可执行
- 执行状态
- 阻塞状态:暂停无法运行,不仅仅只缺少CPU,进程执行后不能再执行的状态
单阻塞队列
查找对应的阻塞进程消耗大
多阻塞队列
- 进程主动完成状态转换还是被动完成?
- 除了执行到阻塞都是被动
- 进程的状态唯一?
- 状态转换与需求关联
- 进程由执行到就绪 的原因
- 抢占,时间片用完
- 单处理机系统中,能否由多个进程处于执行状态
- 不能,多处理机系统可以
空闲进程
创建状态
- 进程创建过程复杂,未完成创建的进程不能调度
- 从开始建立PCB到加入就绪队列转入就绪状态
- 可根据系统性能或主存容量推迟新进程的创建完成,增加管理的灵活性
终止状态
进程终止步骤:
- 等待进程终止的完善
- 撤销进程的PCB
挂起
第三方主动挂起,进程被挂起(阻塞是主动的)
使执行的进程暂停执行,静止下来,使就绪状态的进程暂不接受调度,我们把这种静止状态称为挂起状态
引入挂起的原因
- 终端用户请求
- 父进程请求
- 负荷调节的需要。当实时系统中的工作负荷较重,把一些不重要的进程挂起,以保证系统能正常运行。
- 操作系统的需要。操作系统有时希望挂起某些进程,以便检查运行中的资源使用情况或进行记账
进程管理中的数据结构
大致分为:
- 内存表
- 设备表
- 文件表
- 进程表
PCB
作用
- 作为独立运行基本单位的标志
- 使一个在多道程序环境下不能独立运行的程序(含数据),成立一个能独立运行的基本单位
- PCB是进程存在的唯一标志
- PCB常驻内存(进程的PCB不会被换出)
- 实现间断性运行方式:保存运行时的CPU现场
- 提供进程管理所需要的信息
- 提供进程调度所需要的信息
- 实现与其他进程的同步与通信
进程的上下文也保存在PCB中
信息
- 进程标识符
- 内部:内部标识符是一个唯一的数字标志符.主要是为了方便系统使用
- 外部 :便于用户使用
- 处理机状态(硬件断点,与中断时保存的信息一样)
- 通用寄存器
- 指令计数器
- 程序状态字
- 用户栈指针
- 进程调度信息
- 进程状态:指明当前状态,作为进程调度和对换时的依据
- 进程优先级
- 进程调度所需其他信息:进程已等待CPU的时间总和、 进程已执行的时间总和
- 事件:是指进程有执行状态转变为阻塞状态所等待发生的事件 ,即阻塞原因
- 进程控制信息
- 程序和数据的地址:进程的程序和数据所在的内存或外存地(首)址
- 进程同步和通信机制:指实现进程同步和进程通信时必需的机制, 如消息队列指针、信号量等
- 资源清单:列出了除CPU以外的、进程所需的全部资源及已经分配到该进程的资源的清单
- 链接指针:组织所有进程的数据结构,指出下一个PCB地址
组织方式
- 线性方式
- 项数固定,不便扩展
- 链接方式
- 便于扩展
- 不便于查找,适用于不需要查找的场合
- 索引方式
- 便于快速查找
进程控制
操作系统内核
- OS层次:
通常将一些与硬件紧密相关的模块(如中断处理程序等)、各种常用设备的驱动程序以及运行频率较高的模块(如时钟管理、进程调度和许多模块公用的一些基本操作),都安排在紧靠硬件的软件层次中,将他们常驻内存,即通常被称为的OS内核
OS 内核功能
- 支撑功能
- 中断处理
- 时钟管理
- 原语操作:为了保证正确性 (实现进程的通信和控制)
- 资源管理
- 进程管理
- 存储器(但不提供文件服务)
- 设备
处理机的执行态
- 系统态,管态,内核态
- 处于较高特权,能执行一切指令
- 用户态(目态)
- 较低特权,仅能执行给i顶的指令,访问指定的寄存器和存储区.应用程序只能在用户态运行
目的:保护OS不被破坏
相应地导致用户程序需要获得系统时必须通过系统调用完成。系统调用将导致处理机的执行状态发送转换
原语
定义:由若干指令组成,用于完成一定功能地一个过程,并在执行中不可分割
原子操纵:在一个操作中的所有动作,要么全做,要么全不做。
- 创建进程
- 删除进程
- 阻塞
- 唤醒
- …
在单机系统中采用屏蔽中断的方式来保证操作的原子性
进程的创建
层次结构
- 进程的层次结构一一进程树(进程图)
- 启动过程中第一个进程为根节点
- 子进程会继承(创建时刻继承)父进程的资源
- 父进程打开的文件(文件描述符)
- 进程的内存空间(父进程无法使用子进程的资源)
- IO设备等
- 父进程终止导致子进程终止
- PCB中记录家族关系
- Windows没有进程层次关系
把子进程变成守护进程
父进程变成idle(空进程),子进程关闭终端依赖等
引起创建进程的时间
- 用户登录
- 作业调度(不是进程调度)
- 提供服务
- 应用请求等
创建进程的过程 原语
- 申请空白PCB
- 为新进程分配资源
- 初始化进程控制块
- 如果进程就绪队列能够接纳新进程,就加入就绪队列(可静止就绪,也可活动就绪)
举例
- Fork():复制父进程全部资源——针对父子进程有两次返回(如果创建成功)
- Clone(): 有选择的复制父进程的资源
- Vfork():创建一个线程。复制除tast_struct和系统空间堆栈外的所有资源
都会调用do_fork
进程的终止
事件
- 正常结束
- 批处理系统:Holt指令或终止的系统调用
- 分时系统:Logs off
- 异常结束
- 程序执行非法
- 程序无法运行
- 外界干预
- 操作员或操作系统干预
- 父进程请求终止该进程
- 当父进程终止时,OS也将他的所有子孙进程终止
过程
linux进程终止
- 正常退出
- main中的return
- exit()
- _exit()
- 异常退出
- abort
进程的阻塞和唤醒
阻塞操作时主动的
挂起是第三方对进程的操作
事件
- 请求系统服务而得不到满足时,如问系统请求打印。
- 启动某种操作而需同步时:如该操作和请求该操作的进程需同步运行(即非异步操作)。
- 新数据尚未到达:如进程A写,进程B读,则A未写,完B不能读。
- 无新工作可做
阻塞过程
唤醒过程
进程的挂起和激活
挂起的过程
激活的过程
挂起原语
进程切换
当一个进程占处理机执行完(或不能继续执行),则换另一个进程占处理机执行,称为进程切换。
- 把处理机分配给不同的进程占用执行,称为进程调度。
- 实现分配处理机的程序称为调度程序。
- 在进程切换时,要保护执行现场,称为进程的上下文。
基本步骤
- 保存进程上下文环境
- 更新当前运行进程的控制块内容,将其状态改为就绪或阻塞状态
- 将进程控制块移到相应队列(就绪队列或阻塞队列)
- 改变需投入运行进程的控制块内容,将其状态变为运行状态
- 恢复需投入运行进程的上下文环境
进程同步(重要)
同步:并发进程在执行次序上的协调,以达到有效的资源共享和相互合作,使程序执行有可再现性(封闭性)
基本概念
资源共享和协作导致相关进程间形成制约。
- 两种形式的制约关系
- 资源共享关系:(间接相互制约关系) 需互斥地访问临界资源。
- 相互合作关系:(直接相互制约关系) 因协作而产生阻塞和唤醒,例如共享缓冲区
- 临界资源:(一次仅允许一个进程访问的资源)
- 引起不可再现性是因为临界资源没有互斥访问。
只能互斥访问,无法并发访问
- 引起不可再现性是因为临界资源没有互斥访问。
多个进程需要修改某一数据,系统必须控制,一次仅允许一个进程完成读数据、修改数据(算作一个整体)两件事以后,才允许别的进程对同一数据的读和修改操作
- 临界区:
- 定义:进程访问临界资源的那段代码
- 访问临界资源(上下两个区可以保证临界区互斥访问)
- 进入区:检查有无进程进入
- 临界区:同一时间段只有一个进程
- 退出区:将访问标志复位
- 使用方式
- 如果可以进入,设置临界区使用标志(全局变量),组织其它后来的进程进入临界区
- 后来的进程通过查看临界区使用标志,知道自己不能进入临界区,就进入阻塞队列,将自己阻塞
- 当临界区内的进程使用完毕,退出临界区时,即在**“退出区”修改临界区使用标志**,并负责唤醒阻塞队列中的一个进程,让其进入临界区
临界区使用标志虽然是全局变量,也是临界资源,但是是对大问题的抽象,将大问题简化为一个小问题,之后借助操作系统管理以解决问题
同步机制应遵循的准则(背下来)
- 空闲让进:如果临界区空闲,则只要有进程申请就立即让其进入,以有效利用资源
- 忙则等待:每次仅允许一个进程处于临界区,保证对临界资源的“互斥”访问
- 有限等待:进程只能在临界区内逗留有限时间,不得使其他进程在临界区外陷入“死等”
- 让权等待:进程不能进入临界区时,应立即释放处理机,以免陷入“忙等”状态,进入阻塞队列
硬件同步机制
纯软件同步机制缺点:
- 软件无法解决忙等现象
- 难以控制多个进程的互斥
- 算法设计难度高,容易出现死锁
借助特殊的硬件指令(如Test-and-Set, Swap指令),将操作简化为检查进程锁和关闭锁的操作,将临界资源的访问的问题转变为锁操作(检查、关锁)的原子性
实现方法
- 关中断:只能用于单CPU,可能导致
- 利用Test-and-Set指令实现 :只能实现空闲让进,忙则等待
- 利用Swap指令实现: 只能实现空闲让进,忙则等待
优点
缺点
无法实现有限等待、让权等待
- 存在忙等问题
- 存在饥饿问题
- 存在死锁的可能
信号量机制
实现互斥的基本原理:
- 两个或多个进程可以通过传递信号进行合作,可以迫使进程在某个位置暂时停止执行(阻塞等待),直到它收到一个可以“向前推进”的信号(被唤醒)。
- 相应地,将实现信号灯作用的变量称为信号量。
整型信号量
记录型信号量
信号量类型
- 根据初始值不同:
- 资源信号量:表示资源的分配和回收,初始值大于1,表示某类资源的可用个数
- 互斥信号量:如果初始值为1,用于申请或释放资源的使用权
接口
操作系统内核以系统调用形式提供wait和signal原语,应用程序通过系统调用实现进程间的互斥
Linux信号量
AND型信号量
解决死锁
要么全分配,要么就全不分配
信号量集
应用
- 利用信号量实现互斥:临界区越小越好
- 确定每个运行实体
- 确定哪些资源需要互斥访问(临界资源)
- 为每类资源安排一个信号量
- 每个信号量的初值为1(如果同类资源有多个,设置为资源个数)
- 在访问资源前wait资源对应的信号量
- 在访问完资源后signal对应资源的信号量
mutex m = new mutex;//信号量
m=1;
wait(S)
//临界区操作,读写操作
signal(S)
//其他操作
- 利用信号量来描述前趋关系
- 给关系设置专用的信号量,初值设置为0,阻塞后续操作
- 每个操作如果有前趋,等待每个前趋到自己的信号量
- 完成后,如果有后继,发出对应的signal
管程机制(非考点)
定义了: 数据结构和在该数据结构上的并发进程所执行的一组操作
管程的实现无法有系统操作实现,由高级语言的编译器来完成的
特点
- 局部数据变量只能被管程的过程访问,任何外部过程都不能访问。
- 一个进程通过调用管程的一个过程进入管程。
- 在任何时候,只能有一个进程在管程中执行,调用管程的任何其他进程都被挂起,以等待管程变成可用的。 从而实现进程互斥。
条件变量
为了进行并发处理,管程引入同步工具。条件变量包含在管程中
条件变量由互斥信号量和等待队列构成;互斥信号量用于原语操作的原子性的控制
x.wait:调用进程的执行在条件x上挂起,插入x 等待队列,并释放管程给另一个进程使用
x.signal:恢复在x条件挂起的进程的执行。如果有多个这样的进程,选择其中一个;如果没有这样的进程,什么也不做
同步的经典问题(必考信号量的使用,解决不同情况下进程的互斥)
思路
- 每一个活动实体都是进程,找到活动实体
- 明确实体的活动流程,用伪代码表示出来
- 分析同步和互斥的关系:有哪些需要互斥访问分临界资源?哪些需要同步的关系
同步: 协作,一个在等待,一个在唤醒,并发进程; 互斥: 串行访问
生产消费者问题
一个或多个生产者生产数据,并将生产的数据存入缓冲区,并有一个(也可以多个)消费者从缓冲区中取数据
数据结构:循环队列,in out指针
同步:生产者不能像满缓冲区写数据,消费者不能从空缓冲区读取数据,使用资源信号量empty表示空缓冲区的数量;资源信号量full表示满缓冲区的数量
为什么要使用两个资源信号量
两个资源信号量更适合普遍的环境,如果是网络通信,那生产者生产的消息就是一种资源.
互斥:互斥进入缓冲区,用一个互斥信号量(将整个缓冲区作为一个临界资源)实现
实现方式
- 记录型信号量
互斥信号量成对出现;资源信号量交叉(两个进程协作使用资源)信号量的初始化很重要
- AND信号量
- 利用管程表示
哲学家进餐问题
筷子为临界资源,且不相同,所以用一个信号量表示一只筷子
实现方式
- 记录型信号量
构成死锁
解决方法: - 只允许四个哲学家拿同一边的筷子
读者-写者问题
特点
- 读进程可以共享同一个对象
- 写进程不可共享同一个对象
互斥:两个写进程对一个对象互斥,读写进程对一个对象互斥
同步:读者在读一个对象,写进程被阻塞(对一个文件的读写操作的优先问题)
进程间通信(考得不多,会有一两分)
通信-协作
进程通信需要建立连接,需要同步和协调
-
通信方式: 消息传递、管道、共享存储区等
-
通信内容: 控制信息(信号量的同步)与大批量数据
-
低级通信:交换控制信息的过程(同步与互斥)
- 效率低
- 不透明
-
高级通信:交换里偏高数据
- 使用方便,隐藏细节
- 高效传送大量数据
常用通信机制
- 基于共享存储区
- **不要就数据移动 **
- 利用程序指令设置共享的数据结构
- 由操作系统在内存中划分出一块区域作为共享存储区
- 管道通信
- 单向的
- 消息传递方式(最广泛)
- 直接通信(信息是到达接收方等待队列里)
- 间接通信(信息到达第三方缓冲队列里)
- 信箱
- 私有
- 公共
- 共享:需指明共享的进程
- 信箱
- 客户机和服务器系统
线程
进程的内存空间是隔离的,需要通过通信交互。
如果一个进程要使用多个处理机,就需要将进程分割,这回造成极大的开销(创建进程、撤销进程、进程切换),所以引入线程,以降低时空开销