章节要点
- 基础:进程控制及描述
- 策略:进程调度
- 实现:互斥与同步
- 避免:死锁与饥饿
- 解决:几个经典问题
- 关于:进程通信
2.1 进程的引入
- 程序:源代码程序,目标程序和可执行程序
- 程序执行:编辑,编译,连接,执行
- 程序的结构:顺序结构,分支结构和循环结构
程序顺序执行
- 程序顺序执行的特征:顺序行,封闭性,可再现性
程序并发执行
- 多道程序设计技术:多个程序并发执行
- 程序并发执行时的特征:间断性,非封闭行,不可再现性
程序并发执行引发的问题
- 协调各程序的执行顺序
- 例如:当输入的数据还没全部输入内存时,计算必须等待
- 多个执行程序共享系统资源,程序之间可能会相互影响,甚至影响输出结果
- 选择哪些,多少个程序进入内存执行?
- 内存中的执行程序谁先执行,谁后执行?——进程调度
- 内存如何有效分配?
进程的概念
- 定义:可并发执行的程序,在一个数据集合上运行的过程
- 申请/拥有资源和调度(线程)
- 程序:静态概念,是指令和数据的集合,可长期存储
- 进程与程序对应关系:
- 一个程序可以对应一个进程或多个进程
- 一个进程可以对应一个程序或者一段程序
进程的特征
- 动态性
- 并发性
- 独立性
- 异步性
引入进程带来的问题
- 增加了空间开销:为进程建立数据结构
- 额外的时间开销:管理和协调、跟踪、填写和更新有关数据结构、切换进程、保护现场
- 更难控制:
- 协调多个进程竞争和共享资源如何预防
- 解决多个进程因为竞争资源而出现故障
- 处理机的竞争尤为突出
进程的结构
- 组成(进程印象):程序,数据集合,进程控制块PCB
- PCB是进程存在的唯一标识。创建进程时,创建PCB;进程结束时,系统将撤销其PCB
PCB
- 进程标识信息:进程的内部和外部标识符
- 处理机状态信息:通用寄存器值,指令计数器值,程序状态字PSW值,用户栈指针值
- 进程调度信息:进程状态,进程优先权,进程调度的其它信息
- 其它信息:程序及其数据清单,链接指针
PCB的组织方式
单一队列
- 所有进程的PCB通过链表组织成为一个单一队列。使用于进程数目不多的系统。如:Windows操作系统
方式二:表格结构
- PCB按照进程状态不同,组织成不同的表格:就绪进程表,执行进程表(多机系统中,单击系统中只有一个进程,不需要进程执行表)及阻塞进程表
- 系统分别记载各PCB表的起始地址
(俺这是B站大学,别误会)
某阻塞表==》可以按照不同阻塞信息,分为多种阻塞表
方式三:多级队列
- PCB按照状态不同,用链接指针组成不同队列:就绪进程队列,阻塞进程队列(可按阻塞原因不同,分别组织)
- 系统分别记载各个PCB链表的起始地址
2.2 进程的状态
进程执行轨迹
-
进程的轨迹:进程执行的指令序列,用以观察处理机的执行过程
- 例:假设内存中有3个进程:A,B,C,他们的程序代码已全部装入内存。若A,B两进程需要执行12条执行,C进程需要执行4条指令,且C进程执行到第四条指令处必须等待I/O
-
假设分派程序分派处理机需要依次执行指令序列:s+0,s+ 1,.,s+5
-
进程A的执行轨迹为a+@,a+1,a+2,+3,...
-
进程B的执行轨迹为b+0,b 1,b+2,b+3....
-
进程C的执行轨迹为c+-0,c+1,c+2,c+3,当它执行到c+3指令时遇到了1/O指今,需要释放处理机,进行输入/输出操作
S 操作为分派程序
两状态进程模型
-
两状态:执行,未执行
- 进程获得处理机,进入执行状态;当时间片结束或其它某种原因,进程释放处理机,暂停执行,处于未执行状态。
队列模型
注:
- 并非所有进程只要”未执行“就处于就绪(ready),有的需要阻塞(blocked)等待I/O完成
- “未执行”又可分为就绪和阻塞
- 就绪状态只需要处理机
进程的五个状态
- 执行状态
- 就绪装填
- 阻塞状态
- 新状态
- 终止状态
- 新状态:进程已经创建,但未被OS接纳为可执行进程
- 就绪状态:准备执行
- 执行状态:占用处理机(但处理机环境中国,某一时刻仅一个进程占用处理机)
- 阻塞状态:等待某时间发生才能执行,如等待I/O完成等
- 终止状态:因停止或取消,被OS从执行状态释放
- 空→新状态新创建的进程首先处于新状态。
- 新状态→就绪状态当系统允许增加就绪进程时,操作系统接纳新建状态进程,将它变为就绪状态,插入就绪队列中。
- 就绪状态→执行状态当处理机空闲时,将从就绪队列中选择一个进程执行,该选择过程称为进程调度,或将处理机分派给一个进程,该进程状态从就绪转变为执行。
- 执行状态→终止状态执行状态的进程执行完毕,或出现诸如访问地址越界、非法指令等错误,而被异常结束,则进程从执行状态转换为终止状态。
- 执行状态→就绪状态分时系统中,时间片用完,或优先级高的进程到来,将中断较低优先级进程的执行。进程从执行状态转变为就绪状态,等待下一次调度。
- 执行状态→阻塞状态执行进程需要等待某事件发生。通常,会因为进程需要的系统调用不能立即完成,如读文件、共享虚拟内存、等待I/0操作、等待另一进程与文通信等事件而阻塞。
- 阻塞状态→就绪状态当阻塞进程等待的事件发生,就转换为就绪状态。进入就绪队列排队,等待被调度执行。
注
- 某些系统允许父进程在任何情况下终止其子进程。
- 如果一个父进程被终止,其子孙进程都必须终止。
- 新状态→终止
- 就绪状态→终止
- 阻塞状态—终止
兑换技术,交换技术(swapping)
将内存中暂时不能运行的进程,或暂时不用的数据和程序,换出到外存,以腾出足够的内存空间,把已具备运行条件的程序,或进程所需要的的数据和程序,换入内存。
进程的挂起状态
- 进程被交换到外存,装填变为挂起状态
进程挂起的原因
- 进程全部阻塞,处理机空闲
- 进程全部阻塞,处理机空闲。
- 系统负荷过重,内存空间紧张。
- 操作系统的需要。操作系统可能需要挂起后台进程或一些服务进程,或者某些可能导致系统故障的进程。
- 终端用户的请求。
- 父进程的需求。
被挂起进程的特征
- 不能立即执行
- 可能是等待某事件发生,若是,则阻塞条件独立于挂起条件,即使阻塞事件发生,该进程也不能执行
- 使之挂起的进程为:自身,欺父进程,OS
- 只有挂起它的进程才能使之挂起状态转换为其它状态
- 阻塞→阻塞/挂起:0S通常将阻塞进程换出,以腾出内存空间
- 阻塞/挂起就绪/挂起:当阻塞/挂起进程等待的事件发生时,可以将其转换为就绪/挂起
- 就绪/挂起→就绪:OS需要调入一个进程执行
- 就绪→就绪/挂起:一般,OS挂起阻塞进程。但有时也会起就绪进程,释放足够的内存空间
- 新→就绪/挂起(新→就绪):新进程创建后,可以插入到就绪队列或就绪,挂起队列。若无足够的内存分配给新进程,则需要新→就绪/挂起
2.3 进程的控制
两种执行模式
- 系统模式(又称为系统态)、控制模式或内核模式:
- 具有较高的特权
- 运行系统特定的指令,包括读/写控制寄存器的指令、基本i/o指令以及与存储器管理有关的指令,以及一些特定的内存区
- 内核模式下的处理机机器指令,寄存器和内存都收到完全控制和保护
- 用户模式(或用户态)
- 具有较低的特权
- 用户程序一般运行在用户模式
模式切换
- 用户模式=》系统模式:用户程序执行到一条系统调用,进入操作系统内核执行
- 系统模式=》用户模式执行完系统调用的功能返回到用户程序
- 特殊情况:程序执行难到结束语句时,切换到系统模式,不再返回到用户程序
操作系统内核(Kernel)
- 操作系统的核心,是基于硬件的第一层软件扩充,提供操作系统最基本的功能,是操作系统的基础
- 现代操作系统设计中,为减少系统本身的开销,往往将一些与硬件紧密相关的(如终端处理程序,设备驱动程序等)、基本的、公共的、运行频率较高的模块(如时钟管理,进程调度等)以及关键性数据结构独立开来,是指常驻内存,并对他们进行特殊保护。通常把这一部分称之为操作系统的内核。
- 用户通过系统调用操作系统的功能,这些功能最终都通过操作系统内核实现。
- 不同的操作系统对内核的定义和功能范围的设定是不同的。
- 一般地,操作系统内核的功能可以概括地分为资源管理功能和支撑功能
- 资源管理:进程管理,存储管理和I/O设备管理
- 支撑功能:中断处理、统计、检测、时钟管理、原语操作等
资源管理功能
- 进程管理:进程创建和终止、调度、状态转换、同步和通信、管理PCB
- 存储管理:为进程分配地址空间、对换、段/页管理
- I/0设备管理:缓存管理、为进程分配I/0通道和设备
支撑功能
- 中断处理
- 时钟管理
- 原语(Primitive ):原子操作,最小的操作,不能分割
- 统计
- 监测
进程控制原语
- 进程切换
- 创建与终止
- 阻塞与唤醒
- 挂起与激活
进程创建:原因
- 作业调度(提交新的批处理作业
- 用户登录(交互式用户注册
- 提供服务(操作系统提供服务
- 应用请求(父进程创建子进程
进程创建: 步骤
- 为进程分配一个唯一标识号ID主进程表中增加一个新的表项
- 为进程分配空间:用户地址空间、用户栈空间、PCB空间。若共享已有空间,则应建立相应的链接。
- 初始化PCB:进程标识、处理机状态信息、进程
- 建立链接:若调度队列是链表,则将新进程插入到就绪或就绪/牲起链表
- 建立或扩展其他数据结构
进程终止:原因
- 批处理作业执行到结束语句
- 交互式用户“注销”
- 停止进程(应用程序)的执行
- 遇到错误或故障
进程终止: 具体原因
- 正常结束
- 超时终止,执行时间超过预计时间
- 内存不足,无法为进程分配所需的内存空间
- 越界访问
- 企图使用未允许用的数据,或操作方式错
- 计算错,如除零,或企图存储硬件允许的最大数
- 超时等待某事件发生
- I/0失败,如找不到文件或多次重试仍无法读写文件,或无效操作
- 无效指令,企图执行不存在的指令
- 特权指令,企图执行特权指令·数据类型不符,或未初始化
- 操作员或OS千预,如发生死锁的时候
- 父进程终止·父进程请求
进程终止: 步骤
- 根据被终止进程的标识符ID,找到其PCB,读出该进程的状态;
- 若该进程为执行状态,则终止其执行,调度新进程执行;
- 若该进程有子孙进程,则立即终止其所有子孙进程
- 将该进程的全部资源,或归还给其父进程,或归还给系统
- 将被终止进程(的PCB)从所在的队列中移出、等待其它程序来搜集信息
进程的阻塞与唤醒
- 阻塞原因:请求系统服务;启动某种操作,如I/0;新数据尚未到达;暂时无新工作可做等
- 当出现阻塞事件,进程调用阻塞原语将自己阻塞。并将其状态变为“阻塞状态”,并进入相应事件的阻塞队列;
- 当阻塞进程期待的事件发生,有关进程调用唤醒原语,将等待该事件的进程唤醒。并将其状态变为“就绪状态”,插入就绪队列。
- 一般、讲程可以自己阻塞自已;而唤醒操作则由操作系统,或其它相关进程来完成,进程无法自已唤醒自已。
进程的挂起与激活
- 当出现挂起事件,系统利用挂起原语将指定进程或一个阻塞进程挂起。进程从内存换出到外存,其状态转换:就绪→就绪/挂起
或阻塞→阻塞/挂起 - 当激活事件发生,系统利用激活原语将指定进程激活。将相应进程从外存换入到内存可能的状态转换:就绪/挂起→就绪,或
阻塞/挂起→阻塞
进程A切换到进程B的步骤
- 首先,保护进程A的现场将进程A的当前运行信息,如程序执行到的当前位置,程序状态字,所有的寄存器值等保存到进程A的PCB中。
- 然后,恢复进程B的现场从进程B的PCB中获取其执行信息,将这些信息写入相应的寄存器中,程序计数器指向进程B将执行的下一条指今进程B可能第一次开始执行,也可能是被中断过的进程,恢复执行。不论是哪一种情况,进程B的执行信息都能在其PCB中找到。
进程切换s.模式切换
- 进程切换,作用于进程之间的一种操作。当分派程序收回当前进程的CPU并准备把它分派给某个就绪进程时,该操作将被引用。
- 模式切换,是进程内部所引用的一种操作。当用户程序转入系统调用,或相反时,该操作将被引用。
- 进程切换一定引发模式切换,反之则不然
2.4 进程调度
什么是调度
- 调度是指,在一个队列中,按照某种方法(算法),选择一个合适的个体的过程
- 调度的关键是需要某种方法或算法,好的调度算法有利于选择合适到合适的个体
- 如何判断,设计一个好的调度算法
调度目标
- 公平性,防止进程长期不能获得调度而饥饿;
- 处理机利用率,尽量提高处理机的利用率;
- 提高系统吞吐量;
- 尽量减少进程的响应时间
调度原则
- 满足用户的要求:响应时间、周转时间、截止时间
- 满足系统的需求:系统吞吐量、处理机利用率、各类资源的平衡使用、公平性及优先级
面向用户的原则:响应时间
- 是指,从用户通过键盘提交一个请求开始,直到系统首次产生响应为止的时间。
输入的请求传送到处理机的时闻- 处理机对请求信息进行处理的时间
- 将响应结果发送到输出终端的时间(响应时间)
- 调度算法则应考虑尽可能使绝大多数用户的请求能在响应时闫内完成。
- 常用于评价分时系统的性能。
面向用户的原则:周转时间
- 指从作业提交给系统开始,到作业完成为止这段时间间隔
作业在外存排队等待调度的时间- 进程在就绪队列中等待调度的时间
- 进程被处理机执行的时间
- 等待I/0操作完成的时间(周转时间)
- 常用于评价批处理系统的性能
影响周转时间的调度:
- 作业从外存调度到内存(作业调度)
- 进入内存还需在就绪队列中排队,等待进程调度。
- 甚至,可能会挂起进程,在外存等待被激活(中程调度)
面向用户的原则:截止时间
- 指实时系统中,某任务必须开始执行的最迟时间,或必须完成的最迟时间。
- 常用于评价实时系统的性能.
面向系统的原则:各类资源的平衡使)
- 多道程序系统的目标之一就是为了提高系统资源的利用率,因此,调度算法有责任使系统中的各种资源都尽量处于忙碌状态。
- 该原则同时适用于长程调度和中程调度,因为它们可以决定哪些作业(进程)可以进入内存,可以考虑系统资源的均衡使用。
面向系统的原则:系统吞吐量.
- 指单位时间内系统所完成的作业数
- 常用于评价批处理系统的性能。
- 该原则同时适用于长程调度和中程调度,因为它们可以决定哪些作业(进程)可以进入内存,可以考虑系统资源的均衡使用。
面向系统的原则:公平
- 调度算法应该对所有进程公平,不偏袒任何进程。
面向系统的原则:优先权
- 优先权高的进程应优先调度
- 可以根据进程的优先权不同,组织不同的就绪队列。进程调度时首先选择高优先权队列中的进程,直到该队列空,再调度较低优先权队列中的进程,如图
- 几乎所有操作系统的调度算法都可考虑优先权原则。
- 当然,仅考虑优先权,可能会出现饥饿对低优先权的进程不公平。
- 可以将进程排队的等待时间等因素纳入优先权的计算,随着进程等待时商的增长,其优先权也不断提高,进程也会在不久的将来得到调度
进程调度方式
根据执行进程的处理机是由进程自已释放,还是被强行剥夺,可以将进程调度方式分为非剥夺方式和剥夺方式两种。
进程调度方式:非剥夺
- 执行进程只有在执行完毕,或因申请I/0阻塞自已时,才中断其执行,释放处理机,调度新的进程执行
- 这种方式不利于“即时性”要求较高的分时和实时系统,主要用于批处理系统。
进程调度方式:剥夺方式
- 操作系统可以在新进程到来时,或
- 某个具有较高优先权的被阻塞进程插入就绪队列时,
- 或在基于时间片调度的系统中,时间片用完而中断当前进程的执行,调度新的进程执行。
- 这种方式会产生较多的中断,主要用于实时性要求较高的实时系统及性能要求较高的批处理系统和分时系统。
调度的类型
- 批处理调度、分时调度、实时调度和多处理机调度
- 长程调度(外存调入内存)、中程调度、短程调度
- I/0调度
长程调度(Long-term scheduing)
- 又称高级调度、或作业调度,它为被调度作业或用户程序创建进程,分配必要的系统资源,并将新创建的进程插入就绪以列,等待短程调度。
- 某些采用交换技术的系统将新创建的进程插入到就绪/挂起队列,等待中程调度
- 在批处理系统中,作业进入系统后,先驻留在磁盘上,组织成批处理队列,称为后备队列长程调度从该队列中选择一个或多个作业,为之创建进程。如图:
短程调度(Short-term scheduling)
- 也称进程调度,或低级调度,决定就绪队列中的哪个进程将获得处理机。
- 短程调度运行频率最高。
- 现代操作系统几乎都具有短程调度功能
中程调度(Medium-term scheduling)
- 又称为中级调度。它是对换功能的一部分。
- 当内存空间非常紧张时,或处理机找不到一个可执行的就绪进程时,需要选择一个进程(阻塞或就绪状态)换出到外存,释放出内存空间给别的进程使用;当内存空间较充裕时,从外存选择一个挂起状态的进程调度到内存(换入),见图。
- 目的:为了提高内存的利用率和系统吞吐量
- 只有支持进程挂起的曹邹才具有中程调度功能
进程调度算法-先来先服务(FCFS)
- 该方法按照进程到达的先后顺序排队,每次调度队首的进程。
- FCFS算法属于非剥夺调度方式,实现简单,看似公平。
- 但,对于那些后进入队列而运行时间较短的进程,或I/0型的进程而言,可能需要长时间等待。
分析前面列举的幼儿园一组小孩进食的例子:
-
如果采用FCFS方法,让全部小孩排成一个先进先出的队列,老师从队首开始逐个给小孩喂食,只有当前一个小孩吃饱了,才喂食下一个小孩。那么,排在队列后面的的小孩将长时间不能被喂食而饥饿。
-
特别地,如果排在队列前面的某些小孩需要喂食的时间较长,而排在队列后面的某些小孩只需进食很少的饭量,却需要等待很长的时间。故,该方法对这样的小孩不公平。
-
对短进程不公平。
-
由于长进程可能排在队列前面,必将增加队列后部进程的等待时间,从而将增加平均周转时间。
-
不利于I/0型进程,未有效利用系统资源。
-
一般地,FCFS与其他调度算法混合使用。例如,系统可以按照不同的优先级维护多个就绪队列,每个队列内部按照FCFS算法调度。
-
FCFS算法同时适合于长程、中程和短程调度三种调度类型。
短进程优先
当需要调度进程(或作业)时,通过计算判断就绪进程队列中哪一个进程的预期执行时间最短,或后备作业队列中哪一个或几个作业的预期执行时间最短,就调度谁。
- 属于非剥夺调度算法。当某进程获得处理机,直到其执行完成或需要等待某事件而阻塞时,才自动释放处理机。系统义调度新的进程(或作业)。
- 若采用短进程优先算法调度上例的4个进程,按照进程预期执行时间排序(升序)为P4,P3,P2,PI,试分别计算4个进程的周转时间和他们的平均周转时间。
- 与FCFS算法比较,短进程优先调度算法改善了系统的性能,降低了系统的平均等待时间,提高了系统的吞吐量。但是,该算法也存在一些问题:
- 很难准确预测进程的执行时间;
- 可能导致长进程饥饿,这对长进程不公平
- 采用非剥夺调度方式,未考虑进程的紧迫程度,不适合于分时系统和事务处理系统。
时间片轮转调度法
例如
在一个分时联机系统中,同时有n个人通过各自的终端共享一台主机(服务器)。终端完成输入/输出操作,主机负责处理从终端发来的请求,为之建立进程、协调各进程的坛行、调度各个进程等,并尽量满足每个终端用户对响应时间的要求。
- 在分时联机系统中,n个进程循环地获得时间片而执行。从系统中来看它们是交替执行的,但就每个终端用户而言,都感觉到自已独占了一台主机,不受其他用户的影响。这是通过进程并发执行实现的。
- 如果用户数太多,主机处理的进程将会急剧增加,进程排队等待的时间也会很长,进程的响应时间也可能增长,用户将明显感觉到主机的速度变慢而不满意。
- 另外,时间片的大小也会影响到进程的响应时间
时间片的设置
- 进程切换将会增加系统的额外开销。
- 时间片设定得太短,进程切换会非常频繁,从而降低处理机的效率;时间片设定得太长,将无法满足交互式用户对响应时间的要求。
- 因此,时间片大小的确定应综合考虑系统的最大用户数、响应时间、系统效率等多种因素。
- 采用基于时间片轮转调度算法调度上例的4个进程,并分别按照两种时间片大小轮转调度(1个单位时间和4和单位时间),分析该算法的性能。
- 首先按照进程到达的先后顺序组织就绪队列,即P1,P2, P3, P4。从队首开始调度,首先调度P1,执行一个时间片,强行中断P1,P1回到就绪队列队尾排队;切换到P2,执行一个时间片,强行中断P2, P2回到就绪队列队尾排队(排在P1之后).
时间片轮转调度法
- 常用于分时系统及事务处理系统,合理的时间片大小将带来满意的响应时间。
- 通常,合理的时间片指,能让80%左右的进程(短进程)在一个时间片内完成。
- 对于短的、计算型的进程较有利。
- 不适合于批处理系统的进程调度
- 不利于I/0型的进程。
- 改进的方法之一,可以将I/0阻塞事件完成的进程单独组织一个就绪队列,该队列进程的时间片可以设置的小一些,且优先调度。
基于优先级的调度算
- 基于时间片轮转调度法循环式地为每个被调度的进程分配一个时间片,对每个进程都是公平的。
- 然而,实际应用中,进程的性质可能是不同的。例如,一个与用户进行交互的前台进程急迫地需要对用户的输入作出响应,而一个后俗打印进程的迫切性也许就不那么重要。
- 因此,可以为每个进程定义一个优先级,优先级越高的进程将优先获得处理机的调度。
如何设定进程的优先级
- 进程完成功能的重要性
- 进程完成功能的急迫性
- 为均衡系统资源的使用,指定进程(作业)优先级
- 进程对资源的占用程度例如,可以为短进程(或作业)赋予较高的优先级。
静态与动态优先级
- 静态优先级:一旦确定,则进程运行期间优先级一直不改变。
- 动态优先级:系统首先赋予进程一个初始优先级,该优先级将随着进程的运行而改变。
动态优先级
- 典型的动态优先级变化方式为:
- 优先级随着进程运行的剩余时间的减少而上升,使将要执行结束的进程尽快完成;
- 或随着进程排队等待时间的增长而上升,使等待时间越长的进程优先得到调度,不至长时间饥饿。
- 具体实现方法,可以在每个时钟中断时,或需要进程切换时,重新计算就绪队列中各进程的优先级,并优先调度高优先级的进程。
- 采用动态优先级的两种调度算法:剩余时间最短者优先和响应比高者优先。
剩余时间最短者优先
- 为了使将要结束的进程尽早结束,释放系统资源,让别的进程执行。可以在每个时钟中断时,根据就绪队列中各进的剩余执行时间动态调整其优先级,剩余时间最短的进程优先级最高。
- 显然,该算法是剥夺型的短进程优先调度算法,调度程序总是选择剩余执行时间最短的进程调度执行。
响应比高者优先
将进程的等待时间和进程的预期执行时间纳入优先级的计算,进程(预期执行时间)越长优先级越低,而随着进程的等待时间增长优先级上升,即进程的优先级与等待时间成正比,与进程执行时间成反比。令w表示等待时间,s表示预期执行时间,则响应比;
-
调度方法:若当前执行进程执行完毕,或需要阻塞等待某事件而释放处理机,调度程序选择就绪队列中响应比最大的进程执行。
-
若等待时间相同,短进程因为s较小,R较大而优先调度。若进程的预期执行时间相同,则等待时间长的进程优先调度,相当于FCFS.
-
随着等待时间的增加,长进程的响应比不断增大,在某个时刻,也必然被调度。
-
同短进程优先和剩余时间最短者优先调度算法一样,很难准确估计进程的预期执行时间。
-
每次调度之前都需要计算响应比,增加了系统开销。
反馈调度法
- 前面介绍的几种调度算法都存在各自不同的问题,尤其是短进程优先、剩余时间最短者优先以及响应比高者优先调度算法都需要估计进程的预期执行时间,如果估计不准确,将影响调度结果和系统性能。
- 如果根据进程执行历史,而非未来,进行调度,将解决这个问题。
- 反馈调度法就是一种根据进程执行历史调整调度方式的调度方法,它结合了优先级和时间片轮转调度思想。
- 该方法有利于交互型短进程或短批处理作业,因为它们一般只需要一个或很少的几个时间片即可完成,
- 但可能使长进程的周转时间急剧增加。
- 如果不断地有新进程到来,还可能出现长进程长期饥饿现象。
- 为此,可以为各队列设置不同的时间片,优先级愈低时间片愈长。
进程调度算法小结
- 如何选择进程调度算法与系统设计的目标有关。
- 交互式多任务系统,主要考虑联机用户对响应时间的要求,一般采用基于时间片轮转调度算法,同时,根据进程的性质设置不同的优先级;
- 批处理系统往往以作业的平均周转时间来衡量调度性能,常选用基于优先级的短进程(或作业)优先调度算法。
实时系统(Real-Time System)
- 指,能及时响应外部事件的请求,在规定的时间内完成对该事件的处理,并控制所有实时任务协调一致地运行的计算机系统.
- 分为实时控制系统和实时信息处理系统
实时系统-实时控制系统
-
指要求进行实时控制的系统。
-
主要用于生产过程的控制,实时采集现场数据,并对所采集的数据进行及时处理,进而自动地控制相应的执行机构,使某些(个)参数(如温度、压力、方位等)能按预定的规律变化,以保证产品的质量和提高产量。
-
也可用于武器的控制,如火炮的自动控制系统,飞机的自动驾驶系统,以及导弹的制导系统等。
-
指能对信息进行实时处理的系统。
-
该系统由一台或多台主机通过通信线路连接成百上千个远程终端,计算机接收从远程终端发来的服务请求,根据用户提出的问题,对信息进行检索和处理,并在很短的时间内为用户做出正确的回答。
-
典型的实时信息处理系统有:飞机订票系统,情报检索系统等。
实时任务(real-time task)
-
指,具有及时性要求的、常常被重复执行的特定进程,在实时系统中习惯称为任务。
-
按任务执行时是否呈现周期性来分类:
- 周期性实时任务,要求按指定的周期循环执行,以便周期性地控制某个外部事件。
- 非周期性实时任务,任务的执行无明显的周期性,但都必须联系着一个截止时间(deadline)。
-
截止时间包括:开始截止时间(任务在某时间以前,必须开始执行)和完成截止时间(任务在某时间以前必须完成)。
-
根据对截止时间的要求将实时任务划分为:
- 硬实时任务,系统必须满足任务对截止时间的要求,否则可能出现难以预测的结果
- 软实时任务,它也联系着一个截止时间,但并不严格,若错过了任务的截止时间,对系统产生的影响不会太大。
实时调度的目标
- 主要考虑如何使硬实时任务在其规定的截止时间内完成,同时,尽可能使钦实时任务也能在规定的截止时间内完成。
- 而公平性和最短平均响应时间等要求已不再重要
- 但是,大多数现代实时操作系统无法直替坌理任象的截止时间;它们只能尽量提高响应速度,以尽快地调度任务
实时调度算法
实时性要求不太商的实时系统可用的调度
算法:
- 基于时间片轮转调度算法
- 基于优先级的调度算法
- 最早截止时间优先调度算法,即优先调度截止时间最近的实时任务。
速度单调调度算法(Rate Mottonic Scheduling)
-
根据任务的周期大小赋予优先级,最短周期的任务具有最高优先级、其中,
- 任务周期〔period),指一个任务到达至下一任务到达之间的时间范围。
- 任务连度,印周期(以秒计)的倒数,以赫兹为单位。
-
任务周期的结束,表示任务的硬截止时间,任务的执行时间不应超过任务同期。
-
在RMS调度算法中,如果以任务速度为参数,则优先级函数是一个单调递增的函数,故称为速度单调算法。
-
该调度算法广泛用于工业实时系统的周期性任务调度。
2.5 线程
多线程
- 操作系统中引入进程的目的是为了描述和实现多个程序的并发执行,以改善资源利用率及提高系统的吞吐量。
- 为什么还需要引入线程呢?这是为了减少程序并发执行时系统所付出的额外开销,使操作系统具有更好的并发性。
- 进程的两个基本属性:
- 进程是一个拥有资源的独立单位;
- 进程同时又是一个可以独立调度的基本单位。
系统为进程进行的操作
- 创建进程、撤消进程、进程切换
- 进程作为资源的拥有者和系统的调度对象,需要花费系统较大的额外开销。故,系统中同时存在的进程数目不宜过多,进程切换的频率也不宜过高,而这也就限制了并发度的进一步提高。
由进程到线程
- 目标:既能提高进程并发度,又能降低系统的额外开销。
- 实现:将进程的资源申请和调度属性分开。即进程作为资源的申请和拥有者,但不作为调度的基本单位。这样,就产生了线程的概念。线程是进程中的一个实体,是独立调度和分派的基本单位。
- 线程自身基本上不拥有系统资源,只拥有少许运行中必不可少的私有资源。线程可与同属一个进程的其它线程共享进程的全部资源。
线程的状态
- 进程中的所有线程共享该进程的状态
- 线程具有三种基本状态:就绪、执行和阻塞
- 一般不具有挂起状态,因为线程共享进程的资源,包括存储空间,如果挂起一个进程,其所属的全部进程一定全部被挂起。而单独挂起某进程中的一个线程,必然会影响到同一进程中的其它线程的执行,这是没有任何意义的
对线程的操作
- 一个进程可以创建和撤销一个或多个线程,同意进程中的多个线程可以并发执行。
- 线程的操作包括:
- 派生(Spawn),当系统创建一个进程时,同时也为该进程派生一个线程,同一个进程中的线程可以再派生其它线程
- 阻塞(Block)、当线程需要等待某事件时,它将被阻塞,释放处理机执行其他线程。
- 解除阻塞(Unblock),当线程的阻塞事件,发生,其状态转化为就绪,并插入到就绪队列,等待调度执行。
- 结合(Finish),当线程执行完毕,释放其私有资源
- 注意:线程阻塞不一定引起整个进程的阻塞,否则,引入线程带来的并发性就不会提高
线程与进程
- 传统操作系统中,一个进程可以创建一个线程,如ms,dos就是一个单用户,单进程,单线程的操作系统,Unix是一个多用户,多线程,单线程的操作系统
- 现代操作系统软件设计大多支持多线程运行。例如:java虚拟机就是一个单进程,多线程的运行环境。Windows系列操作系统和Linux操作系统都采用了多进程、多线程技术。
- 传统
并发
- 进程之间可以并发执行
- 同属于一个进程的多个线程之间,亦可以并发执行
- 因而操作系统具有更好的并发性,从而能更有效地使用系统资源和提高系统吞吐量
拥有资源
- 线程是拥有资源的独立单位,它有权申请系统的各种资源
- 线程除了拥有很少的私有资源以外,不能申请系统资源,可以共享其所属进程的资源。即,线程的代码段,手段以及系统资源,如一打开的文件、I/O设备等,都可以被其内的所有线程共享
系统开销
- 操作系统管理进程的开销显著地大于管理线程所需要的的开销
- 进程切换的开销也远大于线程切换的开销
- 由于同一进程中的多个线程具有相同的地址空间,使他们之间的同步和通信也比较容易
- 有些类型的线程切换,同步和通信都无需操作系统内核的干预
线程的类型
- 用户级线程和内核级线程
- 用户级线程的创建、撤消及切换等操作全部由支持线程的应用程序完成,内核并不知道线程的存在。
- 一些数据库管理系统,如Informix即支持用户级线程。应用程序可以利用线程库来设计多线程程序,该线程库包含各种用于管理用户级线程的例程,如用于创建和撤消线程的例程、用于线程间传递消息和数据的例程、线程调度例程,以及保护和恢复线程上下文的例程等,如图2.22 (a)所示。
用户级线程
用户级线程阻塞是否会引起整个进程阻塞呢?
- 这要视具体情况而定。当某进程中的一个线程需要等待另一线程的输出数据而阻塞时,整个进程并不会阻塞。即进程保持执行状态,其内的某个线程也是执行状态。
- 当某线程因为1/0阻塞时,内核需要启动系统I/0,控制从用户级转到系统内核级,这时常会引起整个进程阻塞。随即将发生进程切换,进程调度程序重新调度另一个就绪进程执行。
用户级线程能节省大量的系统额外开销,并提高程序并发性。这是因为:
- 线程的管理和控制仅在用户级进行,线程切换无须内核干预,没有模式切换,减少了模式切换的开销。
- 调度更灵活。应用程序可以根据需要选用线程库中不同的线程调度算法,而不受系统内核进程调度程序的约束。
- 由于线程库独立于系统内核,可以运行在不同的操作系统之上,使用户级线程可以得到不同操作系统的支持,而无须修改操作系统内核。
用户级线程也存在一些问题:
- 由于很多操作系统的系统调用都会引起阻塞,用户级线程中的系统调用常常会引起线程及整个进程阻塞,削弱了线程的并发性。
- 由于系统内核不知用户级线程的存在,可能出现进程切换时,强行中断其内某个执行线程的情况。
- 很难实现不同进程的线程并发。
混合模式
- So1aris操作系统即采用这种技术。
- 在混合模式中,线程的创建、撤消、调度、同步等都在用户级应用程序中完成。
- 应用程序中的多个用户级线程被映射到一个或较少的某些内核级线程。
- 这样,可以使同一应用程序中的多个线程能分散到不同处理机上并行运行。而且,可以避免因为某些用户级线程的阻塞而引起整个进程阻塞的现象。
2.6 进程互斥与同步
可能发生的情况
- 进程P1需要向缓冲区存储数据,并知道in指针当前指向7号空闲缓冲单元。若这时进程P1的时间片用完,被中断,调度程序调度进程P2执行。
- P2正好也需要向缓冲区存放数据;首先获取in指针位置,同样也是7,于是,P2将数据送入7号单元,并将in指针移动一格,指向8号单元,然后继续执行其他操作。
- 当进程P1再次被调度执行时,将从上次的断点继续执行,即将数据送入7号单元(覆盖进程P2的数据),并移动in指针指向8号单元,然后继续执行其他操作。
- 进程P3不会发现上述错误,继续从缓冲区取数据,进行打印。显然,进程P2的相应计算结果不会被打印输出。
分析
- 该例中,由于进程P1和P2共享缓冲区和位置指针,而未对这种共享进行有效控制,导致打印数据的丢失。
- 如果控制进程P1、P2互斥地访问缓冲区和修改位置指针,将避免这种因为并发执行而导致的程序执行结果的不确定性。
结论
通过上述两个例子可见,采用多道程序并发设计技术的操作系统对诸进程的并发控制是非常重要和必需的。
并发控制-竞争资源
-
当并发进程竞争使用同-一资源时,它们之间就会发生冲突
-
如果操作系统将资源分配给其中的某一个进程使用,另一个进程就必须等待,直到申请的资源可用时,由操作系统分配给它。
-
如果竞争某资源的进程太多,这些进程还必须等待在一个队列中,如就绪队列,阻塞队列等
-
一种极端的情况是,被阻塞进程永久得不到申请的资源,而死锁
-
进程竞争资源首先必须解决“互斥”问题。某些资源必须互斥使用,如打印机、共享变量、表格、文件等。
-
这类资源又称为临界资源,访问临界资源的那段代码称为临界区。
-
任何时刻,只允许一个进程进入临界区,以此实现进程对临界资源的互斥访问。
互斥使用临界资源
-
当进程需要使用临界资源时,通过获得临界区的使用权实现的。
-
首先,在“进入区”判断是否可以进入临界区,如果可以进入,则必须设置临界区使用标志,阻止其它后来的进程进入临界区。后来的进程通过查看临界区使用标志,知道自艺不能进入临界区,就进入阻塞队列,将自已阻塞。
-
当临界区内的进程使用完毕,退出临界区时,即在“退出区”修改临界区使用标志,并负责唤醒阻塞队列中的一个进程,让其进入临界区。
-
由于同一个临界资源在多个共享它的进程中将对应多个临界区,那么怎样才能保证诸进程间互斥地执行临界区呢?
-
这就必须保证“临界区使用标志”是可被系统中所有进程共享的全局变量,而且诸进程对该标志的修改操作必须互斥进行。
临界区使用原则(也称为互斥条件)
- 每次只允许一个进程处于临界区(忙则等待);
- 进程只能在临界区内逗留有限时间,不得使其它进程在临界外无限期等待(有限等待)
- 如果临界区空闲,则只要有进程申请就立即让其进入(空闲让进);
- 进入临界区的进程,不能在临界区内长时间阻塞等待某事件,必须在一定期限内退出临界区(让权等待)(同时,如果是在临界区的进程必须退出了临界区才能够申请新的资源)
- 不能限制进程的执行进度及处理机的数量
竞争资源可能引起死锁
- 例如,两个进程P1、P2,竞争资源R1、R2。
- 假设,现在P1已经占用了R1,且P2占用了R2,如果此时P1申请R2,且P2申请R1。会怎么样呢?
- 结果是P1、P2双方都占用对方申请的资源而阻塞,谁也不让步地永久等待,这就是死锁,如图2.25。
竞争资源-饥饿
- 假设有3个进程P1、P2、P3,每个进程都需要周期性的使用资源R。
- 如果当前P1正在使用临界资源R,P2和P3因为等待R而阻塞。
- 当P1退出临界区时,P2立即进入临界区执行,若P2还未退出临界区时,P1又申请使用临界资源R。
- 假设P2退出临界区后,系统将R分给了P1,然后,当R空闲时,又将其分给P2,如此反复。
并发控制-共同协作
-
多个进程常常需要共同修改某些共享变量、表格、文件数据库等,协作完成一些功能。
-
必须确保它们对共享变量的修改是正确的,保证数据的完整性。
-
共享协作同样涉及到互斥、死锁和饥饿问题,但更强调对数据的写操作必须互斥地进行。
-
必须保证数据的一致性。
-
前面列举了银行联网储蓄的例子,除了必须保证储户余额的正确性以外,还必须使银行储蓄总余额、当日发生额、流水帐等数据得到一致的修改。
-
一般通过事务处理来保证数据的一致性,可以将对储户余额、储蓄总余额、当日发生额、流水帐等数据的修改放到一个临界区中,进入临界区的进程必须一次性完成对这一系列数据的修改操作。
并发控制-通信协作
-
当进程进行通信合作时,各个进程之间需要建立连接,进程通信需要同步和协调。进程通信的方式很多,包括消息传递、管道、共享存储区等。
-
通过消息传递实现进程通信时,由于没有共享资源,故无须互斥,但仍可能出现死锁和饥饿。
-
例如,两个进程相互等待对方发来的数据而永久阻塞,即死锁。
-
又如,3个进程P1、P2、P3,其中P1不断尝试与P2或P3通信,P2和P3又不断尝试与P1通信,如果P1与P2总能成功建立连接进行通信,而P3一直阻塞等待P1,这样P3被长时间饥饿。
互斥与同步的解决策略软件方法
- 软件方法
- 硬件方法
- 信号量方法
- 管程方法
- 消息传递方法
软件方法
- 软件方法是指由进程自己,通过执行相应的程序指令,实现与别的进程的同步与互斥,无须专门的程序设计语言或操作系统的支持。
- 实践证明,该方法很难正确控制进程间的同步与互斥,而且可能会大大地增加系统的额外开销,
硬件方法
-
为了解决软件方法存在的不足,有人提出了硬件解决方法,通过屏m中断或采用专门的机器指令控制同步与互斥。
-
与软件解决方法比较,这种方法减少了系统额外开销,但由于需要太强的硬件约束条件,以及可能导致进程饥饿与死锁现象,一直没有成为通用的解决方法。
-
另一类解决方法是由操作系统,或专门的程序设计语言提供的特别支持,包括信号量方法、管程方法和消息传递方法。
-
其中,信号量方法已经成为控制进程同步与互斥的通用方法
互斥与同步解决方法之一:软件方法
- 软件解决方法有很多种,比较有代表性的软件方法有荷兰数学家Dekker提出的Dekker算法和科学家G.L.Peterson提出的Peterson算法。
- 为了说明设计并发程序时可能出现的典型错误,下面以Dekker算法为例,分析如何设计并改讲一个互斥算法的过程。
软件方法-初步设想
- 为了控制两个进程互斥进入临界区,可以让两个进程轮流进入临界区。
- 当一个进程正在临界区执行时,另一个进程就不能进入临界区,而在临界区外等待。
- 程序实现的伪代码如图2.26所示
分析:初步设想
- 保证了互斥
- 问题1:“忙等”现象
- 问题2:进程严格交替进入临界区。如果进程需要多次使用临界区,那么,使用临界区频率低的进程严重制约着使用临界区频率高的进程的执行进度。
例如:
-
P0需要每10分钟使用一次临界区,P1需要每1分钟使用一次临界区。
-
假设turn的初值为0,进程PO正好先请求进入临界区,并成功进入临界区执行,这时,如果P1申请进入临界区,循环检测turn=0,不可以进入,只能“空”循环,等待。
-
当P0退出临界区时,修改turn的值为1。P1循环检测到turn -1时,就可以进入临界区执行,退出临界区时,修改turn=0
-
问题3:任何进程在临界区内或外失败,其他进程将可能因为等待使用临界区,而无法向前推进。
-
因为两个进程相互依赖对方将临界区的使用权(顺序)进行修改,一旦这种修改不能进行,对方都将因为等待临界区而无法推进。
软件方法-第一次改进
-
可以为临界区设置一个状态标志,标明临界区是否可用。当临界区空闲时,任何一个进程都能进入,但此时必须修改临界区标志为“被占用”,别的进程就不能进入临界区。当临界区使用完毕,必需修改该标志为“空闲”。
-
这样就不再使诸进程严格交替使用临界区,而且,如果某进程在临界区外失败,也不会影响其它进程。其算法描述如图2.27所示
分析:第一次改进
- 如果进程在临界区外失败,其他进程不会阻塞
- 问题1:“忙等”,有while就会忙等
- 问题2:若进程在临界区内失败且相应的flag为true,则其他进程永久阻塞。
- 问题3:不能保证进程互斥进入临界区,试着按以下顺序执行:
软件方法-第二次改进
- 互斥算法的第一-次改进不能实现“互斥”。
- 因为,进程首先检测临界区状态,若“被占用”,则“忙等”,否则就直接进入临界区。从而,可能出现同时进入临界区的现象。
- 能否让进程预先表明“希望进入临界区的态度”,然后,再检测临界区状态。第二次改进,如图2.28
分析:第二次改进
-
假设P0需要进入临界区,首先执行f lag[o]:-true,再执行while flag[1],若P1正在占用临界区,则P0忙等;否则,P0进入临界区。
-
但是,如果此时P1未占用临界区,而与P0儿乎同时需要使用临界区,
软件方法-第三次改进
- 互斥算法的第二次改进可能导致死锁,因为P0、P1都“坚持自己的权利,执意进入临界区,且互不谦让”。
- 可以考虑,允许进程既表明需要进入临界区的“态度”,又能相互“谦让”。即首先表示自已需要使用临界区,再检测临界区的状态,若临界区“被占用”,可以等一小段时间再申请
- 算法如图2.29所示
分析:第三次改立
- P0、P1的“谦让”可能使它们都不能进入临界区。
- 这种现象不是死锁,因为这种僵局不会是永久行为,某一时刻可能会自动解除,
- 但是,这种现象也是不希望出现的。
软件方法-Dckken至斥算法
- 该算法既允许进程“谦让地”申请进入临界区,又通过给定序号避免“过分谦让”.
- 伪代码描述如图2.30所示。
软件方法-peterson互斥算法
Peterson互斥算法与Dekker互斥算法的设计思想类似,但代码更简洁,如图2.32所示。
算法中同样用到两个全局共享的状态变星fag[0u]和fag[,表示临界区状态及哪个进程正在占用临界区。
全局共享变址turn(值为0或1)表示能 临界区的进程序号。
硬件方法-屏蔽中断
- 由于进程切换需要依赖中断来实现,如果屏蔽中断,则不会出现进程切换。
- 因此,为了实现对临界资源的互斥使用,可以在进程进入临界区之前,屏蔽中断,当进程退出临界区时,打开系统中断。
- 中断被屏蔽以后,系统时钟中断也被屏蔽。处理机将不会被切换到其他进程。
- 于是,一旦屏蔽中断,进程就可以检查和修改共享内存区中的数据,而不必担心其他进程介入。其伪代码如下:
-
这种方法约束条件太强,付出的代价太大
-
因为中断被屏蔽以后,系统将无法响应任何外部请求,也不会响应当前执行进程的任何异常及系统故障,严重地降低了处理机性能。
-
这种方法仅对单处理机系统有效,如果系统有两个或多个共享内存的处理机,屏蔽中断仅仅对执行本指令的处理机有效,其它处理机仍将继续运行,并可以访问共享内存空间。
硬件方法-专用机器指令
- 利用一些专用机器指令也能实现互斥,机器指令在一个指令周期内执行,不会受到其它指令的干扰,也不会被中断。
- Test and Set指令就是较常用的一种机器指令,其定义如下:
硬件方法-机器指令缺点
- “忙等”现象仍然存在。进程都需要循环检测,等待时机进入临界区。但是,由于采用了机器指令,这种“忙等”消耗的机器时间比软件方法小,属于“可接受的忙等”.
- 可能出现饥饿现象。当临界区空闲时,执行循环检测的若干等待进程能进入临界区的机率是相等的,有的进程可能“运气”非常不好,很难有机会进入临界区,而饥饿。
互斥与同步的解决策略
- 软件方法
- 硬件方法
- 信号量方法
- 管程方法
- 消息传递方法
信号量(semaphores)方法
- 软件方法和硬件方法都存在“忙等”问题,浪费了处理机时间。
- 信号量方法能实现进程互斥与同步,而不必“忙等””
信号量实现互斥的基本原理
- 两个或多个进程可以通过传递信号进行合作,可以迫使进程在某个位置暂时停止执行(阻塞等待),直到它收到一个可以“向前推进”的信号(被唤醒)。
- 相应地,将实现信号灯作用的变量称为信号量,常定义为记录型变量s,其中一个域为整型,另一个域为队列,其元素为等待该信号量的阻塞进程(FIFO)。
定义对信号量的两个原子操作
- wait (s)和signal(s)
- 早期这两个原语被称作P(s)和V(s)
Wait、 signal的应用
- 进程进入临界区之前,首先执行wait(s)原语,若s.count< 0,则进调用阻塞原语,将自己阻塞,并插入到s.queue队列排队。
- 注意,阻塞进程不会占用处理机时间,不是“忙等”。直到某个从临界区退出的进程执行signal(s)原语,唤醒它。
- 一旦其它某个进程执行了signal(s)原语中的s.count +1操作后,发现s.count ≤ 0,即阻塞队列中还有被阻塞进程,则调用唤醒原语,把S.queue中第一个进程修改为就绪状态,送就绪队列,准备执行临界区代码。
信号量的类型
- 信号量分为:互斥信号量和资源信号量。
- 互斥信号量用于申请或释放资源的使用权,常初始化为1.
- 资源信号量用于申请或归还资源,可以初始化为大于1的正整数,表示系统中某类资源的可用个数。
- wait操作用于申请资源(或使用权),进程执wait原语时,可能会阻塞自己
- signal操作用于释放资源(或归还资源使用权),进程执行signal原语时,有责任唤醒一个阻塞进程。
信号量的物理意义
- s.count≥0表示还可执行wait(s)而不会阻塞的进程数(可用资源数)。每执行一次wai(s)操作,就意味着请求分配一个单位的资源
- 当s.count<0时,表示已无资源可用,因此请求该资源的进程被阻塞。此时,s.count的绝对值等于该信号量阻塞队列中的等待进程数。执行一次signal操作,就意味着释放一个单位的资源。若s.count< 0,表示s.queue队列中还有被阻塞的进程,需要唤醒该队列中的第一个进程,将它转移到就绪队列中。
s.count的取值范围
- 当仅有两个并发进程共享临界资源时,互斥信号量仅能取值0、1、-1。其中,
- s.count=1,表示无进程进入临界区
- S.count=0,表示已有一个进程进入临界区
- s.count= - 1,则表示已有一进程正在等待进入临界区
- 当用s来实现n个进程的互斥时,s.count的取值范围为:1~-(n-1)
- 操作系统内核以系统调用形式提供wait和signal原语,应用程序通过该系统调用实现进程间的互斥。
- 工程实践证明,利用信号量方法实现进程互斥是高效的,一直被广泛采用。
经典进程互斥与同步问题
- 生产者/消费者问题
- 读者/写者问题
- 哲学家进餐问题
2.7 生产者/消费者问题
-
生产者与消费者是一个广义的概念,可以代表一类具有相同属性的进程。
-
生产者和消费者进程共享一个大小固定的缓冲区,其中,一个或多个生产者生产数据,并将生产的数据存入缓冲区,并有一个消费者从缓冲区中取数据。