文章目录
- 第二章 并发与进程
-
- 2.1 进程的概念
- 2.2 操作系统为控制程序所建立的数据结构
- 2.3 操作系统对进程的控制
- 2.4 线程
- 2.5 进程调度
- 2.6 实时系统与实时任务调度
- 2.7 并发控制
- 2.8 互斥与同步的解决策略
- 2.9 生产者/消费者问题
- 2.10 读者、写者问题
- 2.11 进程间的通信
- 2.12 进程死锁
第二章 并发与进程
2.1 进程的概念
★ 进程
一个正在执行的程序、正在运行的程序的一个实例、由处理器执行的一个实体
进程 = 进程控制块(PCB) + 程序段 + 数据段 + 栈
- 引入目的:
使多道程序能够正确地并发执行
- 进程的两个基本属性:
– 拥有资源的独立单位:一个进程包括一个保存进程映像的虚地址空间,拥有对资源的控制或所有权。
– 调度/执行的基本单位:一个具有状态和优先级,可被被操作系统调度并分派的实体。
★ 基本特征
- 动态性:(本质特性) 一个正在计算机上执行的程序实例,存在生命周期
- 并发性:(重要特性) 任何进程都可以同其他进程一起向前推进
- 独立性:各进程的地址空间相互独立,除非采用进程间通信手段
- 异步性:按各自独立的、不可预知的速度向前推进
- 结构性
★ 进程的状态转换
- 就绪状态:进程在内存,已分配到除CPU之外的所有必要资源,准备执行
- 执行状态:进程已获得CPU,其程序正在执行。
- 阻塞状态:正在执行的进程由于需要等待某个事件发生而暂时无法继续执行。
- 新建状态:OS已完成为创建一个进程所必要的工作,但进程自身还未进入主存。
- 终止状态:进程完成或发生错误,其表格和其他信息暂时保留。
- 挂起状态:进程交换到外存,不再参与CPU的竞争。<—> 对换技术
- 就绪/挂起:进程在外存,只要调入内存并获得CPU即可执行
- 阻塞/挂起:进程在外存,等待事件
\
进程挂起的原因:进程全部阻塞,处理机空闲;系统负荷过重,内存空间紧张;操作系统的需要,操作系统可能需要挂起后台进程或一些服务进程,或某些可能导致系统故障的进程;终端用户的请求;父进程请求。
2.2 操作系统为控制程序所建立的数据结构
内核的概念:一些与硬件紧密相关、基本的、公共的、运行频率较高的模块,以及关键性数据结构等常驻内存,便于提高操作系统运行效能的这部分软件,称为操作系统的内核。
★ 操作系统内核的功能
- 资源管理功能:进程管理、存储管理、I/O设备管理
- 支撑功能:中断处理、时钟管理、原语操作、统计监测功能
★ 操作系统控制结构
操作系统构造并维护它所管理的每个实体的信息表,一般有4种不同类型的表:内存、I/O、文件和进程。
\
★ 进程控制块
进程控制块的作用: 进程存在的唯一标志;PCB常驻内存。
进程控制块中的信息:
- 进程标示符:唯一地标识一个进程。内部、父、用户标识符
- 处理机状态信息:通用寄存器、指令计数器、程序状态字、用户栈指针
- 进程控制信息:进程状态、进程优先级、进程调度所需的其他信息、事件
- 其他信息:程序和数据的地址、进程同步和通信机制、资源清单、链接指针
进程控制块的组织方式:
2.3 操作系统对进程的控制
2.3.1 进程的创建
引起创建进程的事件
- 用户登录、为新的作业创建进程、操作系统因为提供一项服务而创建、由现有的进程派生
创建进程的步骤:
- 给新进程分配一个唯一的进程标识符
- 为进程分配空间、初始化进程控制块
- 建立链接,将之插入就绪或就绪/挂起链表
- 建立或扩充其它数据结构
2.3.2 进程的撤销
引起进程终止的事件
- 正常结束、异常结束(越界错误、保护错、非法指令、特权指令错、运行超时、等待超时、算术运算错、I/O故障)、外界干预(程序员kill进程、父进程终止、父进程请求)
进程终止的步骤
- 根据被终止进程的标识符找到其PCB,读出该进程的状态
- 若该进程为执行状态,则终止其执行,调度下一个就绪进程执行
- 若该进程还有子孙进程,还应将其所有子孙进程予以终止
- 将该进程所拥有的全部资源,或者归还给其父进程,或者归还给系统
- 将被终止进程的PCB从所在队列中移出
2.3.3 进程的阻塞
引起阻塞的事件
- 请求系统服务而得不到满足、启动某操作而需同步、新数据尚未到达、无新工作
进程阻塞的步骤
- 进程通过调用阻塞原语block( )把自己阻塞
- 将PCB中的状态由“执行”改为“阻塞”,并将PCB插入阻塞队列
- 调度程序将处理机分配给另一就绪进程,并进行切换
2.3.4 进程的唤醒
- 由有关进程调用唤醒原语wakeup( )将等待该事件的进程唤醒
- 被阻塞的进程从等待该事件的阻塞队列中移出
- 将其PCB中的现行状态由阻塞改为就绪
- 将该PCB插入到就绪队列中
2.3.5 进程的挂起
引起挂起suspend( )的事件
- 内存资源紧张、进程全部阻塞,CPU空闲
程序挂起的步骤:
- 检查被挂起进程的状态,若处于就绪状态,便将其改为就绪/挂起
- 对于处于阻塞状态的进程,则将之改为阻塞/挂起
- 将进程移出内存
2.3.6 进程的激活
- 将进程从外存处于挂起状态的进程调入内存,激活原语active()
- 检查该进程的现行状态: 若是就绪/挂起,便将之改为就绪;若为阻塞/挂起,便将之改为阻塞
2.3.7 进程切换
概念:调度另一个就绪进程占用处理器执行
何时发生:时钟中断、I/O中断、内存失效、陷阱、系统调用
进程切换的步骤:
- 保存处理器上下文环境,包括程序计数器和其它寄存器
- 更新当前处于运行状态进程的进程控制块
- 将进程的进程控制块移至相应队列(就绪、阻塞等)
- 选择另一进程执行
- 更新其进程控制块信息
- 恢复被选择进程的上下文环境
★ UNIX进程控制
fork():创建一个新进程。
调用格式: pid = fork()
在调用fork()之后,父进程和子进程均在下一条语句上继续运行。在子进程中返回时,pid为0;在父进程中返回时,pid为所创建的子进程的标识。
2.4 线程
2.4.1 线程的概念
概念:线程又叫轻量级进程,进程的一个实体,是系统独立调度和分派的基本单位。
优势:增加系统的并发性,减少并发执行时的时空开销。
属性
- 除了一点必不可少的资源(如TCB、程序计数器、寄存器和堆栈)外,线程基本
上不拥有系统的资源
- 独立调度和分派的基本单位
- 同一个进程中的多个线程以及不同进程中的多个线程均可并发执行
- 同一个进程中的各线程可以共享该进程中所拥有的全部资源,如进程的地址空
间、已打开的文件、定时器和信号量等
2.4.2 进程与线程的关系
\
2.4.3 多线程并发
线程的基本状态:
线程的基本操作:
- 派生:线程可以由进程或线程所派生
- 阻塞:等待某事件,并释放处理机
- 解除阻塞:等待的事件发生,状态变成就绪,插入就绪队列,等待调度执行。
- 结束:执行完毕,释放其私有资源
2.4.4 线程的类型
- 用户级线程:操作由应用程序完成;操作系统不知道线程存在,仍以进程为调度单位。
- 内核级线程:操作由系统内核完成,以线程为调度单位。
- 混合线程:操作由应用程序完成,多个用户级线程被影射到一个或较少的某些内核级线程
2.5 进程调度
2.5.1 调度的目标和原则
目标:防止饥饿、提高处理器的利用率、提高系统吞吐量、减少响应时间
原则:用户的需求(响应时间快、平均周转时间短、满足截止时间)、系统的需求(吞吐量大、CPU利用率高、各类资源的平衡使用、公平性、优先权)
2.5.2 调度的类型
长程调度(高级调度、作业调度):
- 决定外存上处于后备队列中的哪个作业调入内存
- 为它们创建进程、分配必要的资源
- 将新创建的进程排在就绪队列(就绪/挂起)上,等待短程(中程)调度。
中程调度(中级调度)
- 对换功能的一部份,用以提高内存的利用率和系统的吞吐量。
- 内存紧张时,选择一个进程换出到外存(换出)。
- 内存充裕时,从外存选择一个挂起状态的进程调度到内存(换入)。
- 只有支持进程挂起的操作系统才具有中程调度功能
短程调度(进程调度、低级调度)
- 决定就绪队列中的哪个进程应获得处理器
- 运行频率最高
- 现代操作系统几乎都具有短程调度功能
2.5.3 一些相关的基本概念
- 响应时间:从用户通过键盘提交一个请求开始,直至系统首次产生响应为止的时间。
响应时间 = 输入传送时间 + 处理时间 +响应传送时间
- 周转时间:从作业被提交给系统开始,到作业完成为止的时间。
= 驻外存等待调度时间 + N *(驻内存等待调度时间+执行时间+阻塞时间)
- 带权周转时间:作业的周转时间与系统为它提供服务的时间之比。
- 截止时间:某任务必须开始执行的最迟时间,或必须完成的最迟时间。一般用于实时系统。
- 系统吞吐量:在单位时间内系统所完成的作业数。
2.5.4 调度的分类
按是否剥夺当前进程来分:非剥夺方式、剥夺方式
按被调度进程的状态来分:长程调度、中程调度、短程调度
2.5.5 常见的调度算法
2.6 实时系统与实时任务调度
实时系统的基本要求:
可确定性、可响应性、用户控制、可靠性、失效弱化
实时任务的分类
按截止时间分:硬实时任务、软实时任务
按周期性分:周期性任务、非周期性任务
实时调度的目标
使硬实时任务在其规定的截止时间内完成(或开始),同时尽可能使软实时任务也能在规定的截止时间内完成(或开始)。
★ 常见的实时调度算法
(1) 基于时间片轮转的调度 秒级,用于分时、一般实时处理系统
(2) 基于优先级的非抢占调度 百毫秒~数秒级,用于多道批处理系统
(3) 基于优先级的抢占点抢占调度 几毫秒~几十毫秒,一般实时系统
(4) 立即抢占式调度 毫秒级,苛刻的实时系统
(x) 限期(deadline)调度: 最早截止时间优先调度算法(EDF)
最低松弛度优先调度算法(LLF)
速度单调调度算法(RMS)
松弛度=完成截止时间-剩余执行时间-当前时间
2.7 并发控制
★ 相关概念
临界资源:一次仅允许一个进程访问的资源为临界资源
临界区:把在每个进程中访问临界资源的那段代码称为临界区。临界区是一段代码,在这段代码中进程将访问临界资源,当另外一个进程已经在这段代码中运行时,这个进程就不能在这段代码中执行。
死锁:两个或两个以上的进程相互等待导致都不能执行
互斥:当一个进程在临界区访问临界资源时,其他进程不能进入该临界区访问共享资源
竞争:多个进程读写一个共享数据时依赖它们执行的相对时间
饥饿:一个进程已经完全具备了执行的条件,但是得不到CPU资源
★ 进程间的制约关系
间接制约:资源共享–>互斥
直接制约:进程合作–>同步
★ 临界区使用原则(互斥条件)
- 空闲让进:如临界区空闲,则有进程申请就立即进入。
- 忙则等待:每次只允许一个进程处于临界区。
- 有限等待:保证进程在有限时间内能进入临界区。
- 让权等待:进程在临界区不能长时间阻塞等待某事件。
2.8 互斥与同步的解决策略
★ 软件方法
在进入区设置和检查一些标志来标明是否有进程在临界区。若已有进程在临界区,则在进入区通过循环检查进行等待,进程离开临界区后则在退出区修改标志。
始终存在忙等问题。
通常能实现两个进程的互斥,很难控制多个进程的互斥。
★ 硬件方法
屏蔽中断:避免进程切换,实现互斥访问。
专用机器指令:设计专门的机器指令用于保证动作的原子性,如Test&Set、Exchange。
硬件方法支持多处理机和多临界区,但存在忙等、饥饿和死锁的现象。
★ 信号量方法
信号量实现进程互斥的基本原理
- 两个或多个进程可以通过传递信号进行合作,可以迫使进程在某个位置暂时停止
执行(阻塞等待),直到它收到一个可以“向前推进”的信号(被唤醒)。
- 信号量s一个域为整型,另一个域为队列(等待该信号量的阻塞进程们)
信号量的定义
信号量的两个原子操作
信号量的类型
- 互斥信号量:用于申请或释放资源的使用权,初始值为1。范围: [ -(n-1), 1 ] 。
- 资源信号量:用于申请或归还资源,表示某资源的可用数目。范围: [ m-n, m]
n个进程共享临界资源: -(n-1)≤s.count ≤1
★ 管程
管程是一个程序设计语言结构,采用了集中式的进程同步方法,提供了与信号量同样的功能,但更易于控制。一个管程定义了一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据。(C. A. R. Hoare & Per Brinch Hansen)
管程是由一个或多个过程、一个初始化序列和局部数据组成的软件模块。主要特点:
- 局部数据变量只能被管程的过程访问,任何外部过程都不能访问。
- 一个进程通过调用管程的一个过程进入管程。
- 在任何时候,只能有一个进程正在管程执行,调用管程的任何其它进程都被阻塞,以等待管程可用。
2.9 生产者/消费者问题
- 应先申请资源信号量,再申请互斥信号量,顺序不能颠倒。
- 同一进程中的多对wait和signal语句可以嵌套,也可以交叉。
- 对于同一个信号量的wait与signal操作,既可以出现在同一个进程中,也可以出现在不同进程中。
- 对任何信号量的wait与signal操作必须配对。
- 在进入临界区前必须先执行wait操作,退出临界区后必须执行signal操作。对于同一信号量而言,既有可能先执行wait操作,也有可能先执行signal操作。
★ 1个生产者、2个消费者被连接到大小为N的缓冲区上,2个消费者分别消费不同资源
- 盘子是一互斥资源,故设置互斥信号量mutex(1)
- 爸爸、儿子因为桔子的放入与取出而同步,设置资源信号量orange(0)
- 爸爸、女儿因为苹果的放入与取出而同步,设置资源信号量apple(0)
- 爸爸、儿子、女儿因为共享盘子,设置资源信号量empty(N)
★ 2个生产者、2个消费者被连接到大小为1的缓冲区上,2个生产者分别生产不同的资源,2个消费者也分别消费不同的资源
- 盘子是一互斥资源,故设置互斥信号量plate(1)
- 爸爸、女儿因为苹果的放入与取出而同步,设置资源信号量apple(0)
- 妈妈、儿子因为桔子的放入与取出而同步,设置资源信号量orange(0)
★ 2个生产者、1个消费者被连接到大小为2的缓冲区上,2个生产者分别生产不同的资源,当两种资源同时存在时消费者才能进行消费
- 盘子是一互斥资源,故设置互斥信号量mutex(1)
- 盘子中是否可以放入苹果,设置信号量empty_apple(1)
- 盘子中是否可以取出苹果,设置信号量apple(0)
- 盘子中是否可以放入桔子,设置信号量empty_orange(1)
- 盘子中是否可以取出桔子,设置信号量orange(0)
★ 1个生产者、2个消费者被连接到大小为1的缓冲区上,每个数据被消费两次才结束生命周期,消费者可以同时消费同一数据
- 爸爸是否欣赏过,设置资源信号量empty_dad(1)
- 爸爸是否可以欣赏,设置资源信号量full_dad(0)
- 妈妈是否欣赏过,设置资源信号量empty_mom(1)
- 妈妈是否可以欣赏,设置资源信号量full_mom(0)
2.10 读者、写者问题
允许多个读者进程可以同时读数据;
不允许多个写者进程同时写数据,即只能互斥写数据;
若有写者进程正在写数据,则不允许读者进程读数据——互斥读写。
★ 读者优先
一旦有读者正在读数据,则允许随后的读者进入读数据。只有当全部读者退出,才允许写者进入写数据。导致写者饥饿
- wsem:互斥信号量,用于Writers互斥Writers和Readers,以及第一个Reader互斥Writers。(1)
- readcount:统计同时读数据的Readers个数(int型/0)
- mutex:对变量readcount互斥算术操作(1)
★ 公平优先
读者、写者的执行顺序与到达顺序严格一致。
- wsem:互斥信号量,用于…
- readcount:统计同时读数据的Readers个数(int型/0)
- mrc:对变量readcount互斥算术操作(1)
- wrsem:互斥信号量,确定Writer 、Reader请求顺序(1)
★ 写者优先
只要有一个写者申请写数据,则不再允许新的读者进入读数据。解决了写者饥饿问题,但降低了并发程度,系统的并发性能较差。
- rsem:互斥信号量,当至少有一个写者申请写数据时互斥新的读者进入读数据(1)
- wsem:互斥信号量,用于…(1)
- readcount:统计同时读数据的Readers个数(int/0)
- writecount:用于控制rsem信号量(int/0)
- mrc:对变量readcount互斥算术操作(1)
- mwc:对变量writecount互斥算术操作(1)
2.11 进程间的通信
进程通信:进程之间的信息交换
★ 共享存储区
★ 消息传递
两条通信原语:Send(destination,message)、Receive(source,message)
三种同步方式:
- 阻塞发送,阻塞接收;
- 不阻塞发送,阻塞接收;
- 不阻塞发送,不阻塞接收
邮箱:不不限制进程数,允许多个发送进程向邮箱发送消息,同时,也允许多个接收进程从邮箱接收消息
利用消息传递实现互斥
- 共享一个邮箱,初态仅包含一条空消息;
- 采用“不阻塞发送,阻塞接收”方式传递消息;
- 若邮箱中存在一条消息,则允许一个进程进入临界区。
- 若邮箱为空,表明有一个进程位于临界区,其它试图进入临界区的进程必须阻塞。
- 只要保证邮箱中最多只有一条消息,就能保证只允许一个进程进入临界区,从而实现进程互斥使用临界资源。
利用消息传递解决生产者/消费者问题
- 使用capacity条消息,其作用类似于缓冲区的大小;
- capacity条消息的初始状态为“空”消息,类似于缓冲区的初始状态为空(未填充生产数据);
- 生产者生产一条数据后,取一条“空”消息,并发送回一条填充了数据的消息;
- 消费者消费一条数据后,取一条填充了数据的消息,并发送回一条“空”消息;
- 若生产者速度快于消费者消速度,则因无“空”消息可用而阻塞;
- 若消费者速度快于生产者消速度,则因无填充了数据的消息可用而阻塞。
2.12 进程死锁
★ 死锁的概念
多个进程因为竞争资源或执行时推进的顺序不当,或相互通信出现永久阻塞现象,如果没有外力作用,这种现象将永远保持下去。
★ 产生死锁的原因
★ 产生死锁的充分必要条件
- 互斥、占有且等待、非剥夺条件是死锁产生的必要条件,但不是充分条件。
- 循环等待条件实际上是互斥、占有且等待、非剥夺条件的可能导致的结果。
- 只要系统出现循环等待,则一定出现死锁。
- 互斥、占有且等待、非剥夺条件、循环等待条件构成了死锁产生的充分必要条件。
★ 解决死锁的方法
- 预防 :添加限制条件,破坏产生死锁的条件(四个必要条件中的一两个)
- 避免 :动态检查,防止系统进入不安全状态。银行家算法
- 忽略 :鸵鸟策略
- 检测解除:允许死锁,但(不)定期检测死锁并解除
死锁检测:(死锁定理:)状态S为死锁状态的充要条件是:当且仅当S状态的资源分配图是不可完全简化的。
死锁解除:撤销进程、资源剥夺、进程回退
★ 安全性算法
★ 银行家算法
设计思想:当用户申请一组资源时,系统必须做出判断:如果把这些资源分出去,系统是否还处于安全状态。若是,就可以分配这些资源;否则,暂时不分配,阻塞进程。
银行家算法的使用:
(1)首先根据安全性算法判断初始时刻系统是否处于安全状态,如果是,则继续往下进行。
(2)当某进程请求资源时,根据银行家算法判断是否对其分配资源。
(3)循环执行(2)。直到所有进程都顺利完成。
★哲学家就餐问题
方案一:为餐叉编号;就餐前,先取用编号较低的餐叉,再取用编号较高的餐叉;就餐毕,先放下编号较高的餐叉,再放下编号较低的餐叉。
方案二:为哲学家编号;奇数号的哲学家必须首先拿左边的餐叉;偶数号的哲学家必须首先拿右边的餐叉。
方案三:引入一个餐厅服务生,哲学家必须经过他的允许才能拿起餐叉;最多允许4个哲学家同时进食。
方案四:仅当哲学家的左右手筷子都拿起时才允许进餐。多个临界资源,要么全部分配,要么一个都不分配。