22-1进程与线程(调度)
进程、线程基本概念
程序:
- 静态的,就是个存放在磁盘里的可执行文件
- 如:QQ.exe
进程:
- 动态的,是程序的一次执行过程
- 如:可同时启动多次QQ程序
- 同一个程序多次执行会对应多个进程
- 一个进程中包括PCB、程序段、数据段三部分
- PCB是给操作系统用的,PCB是进程存在的唯一标志
- 程序段、数据段是给进程自己用的,与进程自身的运行逻辑有关
程序段:程序的代码,即指令序列
数据段:运行过程中产生的各种变量。如程序中定义的变量
PCB
进程的信息都被保存在一个数据结构PCB (Process Control Block)中,即进程控制块
- 操作系统需要对各个并发运行的进程进行管理,但凡管理时所需要的信息,都会被放在PCB中
- 当进程被创建时,操作系统为其创建PCB,当进程结束时,会回收其PCB
PCB包含以下信息:
- 进程描述信息:
- 基本的进程描述信息,可以让操作系统区分各个进程
- 进程表示符PID:
- 当进程被创建时,操作系统会为该进程分配一个唯一的、不重复的"身份证号"—— PID(Process ID,进程ID)
- 用户标识符UID:
- 在多用户操作系统中,每个用户账号都分配唯一的uid,用于区分不同用户的所有权和全西安
- 进程中的UID一般表示进程的创建者,具有进程的所有权限
除了UID以外,还保留有EUID,表示进程进程对于文件和资源的放权权限,相当于具备用户所拥有的文件访问权限
- 进程控制和管理信息:
- CPU、磁盘、网络流量使用情况统计信息
- 进程当前状态:就绪态、组赛太、运行态等状态信息
- CPU、磁盘、网络流量使用情况统计信息
- 资源分配清单:
- 正在使用的文件清单
- 正在使用哪些内存区域
- 正在使用哪些I/O设备
- 处理机相关信息:
- 用于实现进程切换的信息
- 如PSW、PC等等各种寄存器的值
- 用于实现进程切换的信息
同时挂三个QQ号,会对应三个QQ进程,它们的PCB、数据段各不相同,但程序段的内容都是相同的(都是运行着相同的QQ程序)一个进程被"调度",就是指操作系统决定让这个进程上CPU运行
程序的运行
- 开发人员使用高级语言代码进行编写,经过编译器编译生成对应功能的机器指令序列,即可执行程序
- 程序开始运行前,需要在主存中创建对应的进程,以告知操作系统程序执行状态,即在主存中创建PCB
- 可执行程序运行过程,会将程序的机器指令序列加载到内存中,即进程的代码段
- 程序运行过程中产生的各种数据也保存在贮存内,即进程的数据段
程序段、数据段、PCB三部分组成了进程实体(进程映像)
- 进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位
- 一个进程被"调度",就是指操作系统决定让这个进程上CPU运行
进程的特征
动态性:
- 进程是程序的一次执行过程,是动态地产生、变化和消亡的
- 动态性是进程的最基本特征
并发性:
- 内存中有多个进程实体,各进程可以并发执行
独立性:
- 进程是能独立运行、独立获得资源、独立接受调度的基本单位
异步性:
- 各进程按各自独立的、不可预知的速度向前推进,操作系统要提供"进程同步机制"来解决异步问题
- 异步性会导致并发程序执行结果的不确定性。具体会在"进程同步"相关小节进行学习
结构性:
- 每个进程都会配置一个PCB。结构上看,进程(实体)由程序段、数据段、PCB组成
进程的状态与转换
创建态:New,又称新建态
- 进程正在被创建时,它的状态是"创建态",在这个阶段操作系统会为进程分配资源、初始化PCB
就绪态:Ready
- 当进程创建完成后,便进入"就绪态",处于就绪态的进程已经具备运行条件
- 但由于没有空闲CPU,就暂时不能运行
- 系统中可能会有很多个进程都处于就绪态
运行态:Running
- 如果一个进程此时在CPU上运行,那么这个进程处于"运行态",CPU会执行该进程对应的程序(执行指令序列)
- 单CPU情况下,同一时刻只会有一个进程处于运行态,多核CPU情况下,可能有多个进程处于运行态
- 当CPU空闲时,操作系统就会选择一个就绪进程,让它上处理机运行,并分配给他所需的资源
- 进程在获得所需资源之前,进程无法再往下执行
阻塞态:Waiting/Blocked,又称等待态
- 在进程运行的过程中,可能会请求等待某个事件的发生(如等待某种系统资源的分配,或者等待其他进程的响应)。在这个事件发生之前,进程无法继续往下执行,此时操作系统会让这个进程下CPU,并让它进入"阻塞态"
- 由于当前运行的进程处于阻塞态,CPU空闲时,又会选择另一个"就绪态"进程上CPU运行
- 当等待的事件发生时,进程从"阻塞态"回到"就绪态"
运行状态、就绪状态、阻塞状态是进程的三种基本状态,进程的整个生命周期中,大部分时间都处于三种基本状态
终止态:Terminated,又称结束态
- 一个进程可以执行exit系统调用,请求操作系统终止该进程。此时该进程会进入"终止态",操作系统会让该进程下CPU,并回收内存空间等资源,最后还要回收该进程的PCB
- 当终止进程的工作完成之后,这个进程就彻底消失了
进程状态转换

- 运行态->阻塞态是一种进程自身做出的主动行为
- 阻塞态->就绪态不是进程自身能控制的,是一种被动行为
- 由于进入阻塞态是进程主动请求的,进程不能由阻塞态直接转换为运行态,也不能由就绪态直接转换为阻塞态,必然需要进程在运行时才能发出这种请求
进程的组织
进程PCB中,会有一个变量state 来表示进程的当前状态。如:1表示创建态、2表示就绪态、3表示运行态...
- 为了对同一个状态下的各个进程进行统一的管理,操作系统会将各个进程的PCB组织起来
链式方式:
- 操作系统按照进程状态讲PCB分为多个队列,操作系统持有只想各个队列的指针

- 阻塞队列指针会指向当前处于阻塞态的进程,很多操作系统还会根据阻塞原因不同,再分为多个阻塞队列
索引方式:
- 操作系统根据进程状态的不同,建立几张索引表,操作系统持有指向各个索引表的指针

大多数操作系统采用链式方式
进程控制
进程控制:
- 主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能,即实现进程状态转换
- 进程控制需要保证过程不可被打断,依赖于操作系统的原语功能实现

- 假设PCB中的变量state 表示进程当前所处状态,1表示就绪态,2表示阻塞态
- 此时进程2等待的事件发生,则操作系统中,负责进程控制的内核程序至少需要做这样两件事:
- PCB2的state 设为1
- 完成了第一步后收到中断信号,那么PCB2的state=1,但是它却被放在阻塞队列里
- 将PCB2从阻塞队列放到就绪队列
进程原语实现:
- 正常情况下,CPU每执行完一条指令都会例行检查是否有中断信号需要处理,如果有,则暂停运行当前这段程序,转而执行相应的中断处理程序
- 中断处理结束之后也不一定会直接回到原进程执行
- CPU执行了关中断指令之后,就不再例行检查中断信号,直到执行开中断指令之后才会恢复检查
- 关中断、开中断之间的这些指令序列就是不可被中断的,从而实现了"原子性"、
如果开、关中断指令允许用户执行,那么会导致用户程序触发开中断指令后,独占着CPU直至自行关中断,显然是不允许发生的
进程创建:
- 创建原语:操作系统创建一个进程时使用的原语
- 申请空白PCB
- 为新进程分配所需资源
- 初始化PCB
- 将PCB插入就绪队列,即创建态 -> 就绪态
- 引起进程创建的事件:
- 用户登录时
- 如,分时系统中,用户登录成功,系统会为其建立一个新的进程
- 作业调度:
- 如,多道批处理系统中,有新的作业放入内存中,会为其建立一个新的进程
- 提供服务:
- 如,用户向操作系统提出某些请求时,会新建一个进程处理该请求
- 应用请求:
- 如,由用户进程主动请求创建一个子进程
- 用户登录时
进程终止:
- 撤销原语:就绪态/阻塞态/运行态 -> 终止态 -> 无
- 从PCB集合中找到终止进程的PCB
- 若进程正在运行,立即剥夺CPU,将CPU分配给其他进程
- 终止其所有子进程
- 进程间关系是树形结构,父进程被终止,其子、孙所有子进程全部终止
- 将改进程用户的所有资源归还给父进程或操作系统
- 子进程的资源均来源于父进程,除了0号进程
- 1号进程是所有其他用户进程的祖先进程,系统启动后完成系统的初始化,随后变为守护进程用于监视系统其他进程
- 1号进程由0号进程创建,0号进程是唯一一个没有父进程的进程,用于进程调度、交换
参考自https://www.cnblogs.com/alantu2018/p/8526970.html
- 子进程的资源均来源于父进程,除了0号进程
- 删除PCB
- 引起进程终止的事件:
- 进程正常结束时
- 如,进程自己请求终停止,使用exit系统调用
- 进程异常结束时
- 如,整数除以0、非法使用特权指令,然后被操作系统强行杀掉
- 外界干预时
- 如,Ctrl+ALT+delete,用户选择杀掉进程
- 进程正常结束时
进程阻塞:
- 阻塞原语:运行态 -> 阻塞态
- 找到要阻塞的进程对应PCB
- 保护进程运行现场,将PCB状态信息设置为"阻塞态",暂时停止进程运行
- 引起进程阻塞的事件:
- 需要等待系统分配某种资源时
- 需要等待相互合作的其他进程完成工作时
进程唤醒:
- 唤醒原语:阻塞态 -> 就绪态
- 在时间等待队列中找到PCB
- 将PCB从等待队列溢出,设置进程为就绪态
- 将PCB插入就绪队列,等待被调度
- 引起进程唤醒的事件:
- 等待事件的发生时:因什么事件阻塞,就应该由什么事件唤醒
阻塞原语和唤醒原语必须成对使用
进程切换:
- 切换原语:运行态 -> 就绪态,就绪态 -> 运行态
- 将运行环境信息存入PCB
- 运行环境信息即进程上下文Context
- PCB移入相应队列
- 选择另一个进程执行,并更新其PCB
- 根据PCB恢复新进程所需的运行环境
- 将运行环境信息存入PCB
- 引起进程切换的事件:
- 当前进程时间片结束时
- 由更高优先级的进程到达时
- 当前进程主动阻塞
- 当前进程终止
进程控制程序运行过程

- 程序运行后,在主存中创建PCB,程序段和数据段
- CPU会按照程序段中的指令序列,逐条执行指令,会与寄存器发生数据交换,例如PSW程序状态字寄存器、PC程序计数器、IR指令寄存器、通用寄存器
- 该进程所需要使用的数据除了数据段中保存的变量信息外,上述提到的寄存器中也存放着后续指令所需的数据
- 如果发生进程切换,新进程不可避免也需要使用到这些寄存器,那么在切换前就需要保存这些包含必要信息的寄存器,操作系统会将这些信息保存在PCB中
- 当进程发生切换时,会将PCB中的现场信息进行恢复,覆盖到现在的寄存器中,用于执行当前的指令
进程上下文Conext,运行环境信息一般就是指执行指令时需要的寄存器信息
无论哪个进程控制原语,要做的无非三类事情:
- 更新PCB中的信息
- 所有的进程控制原语一定都会修改进程状态标志
- 剥夺当前运行进程的CPU使用权必然需要保存其运行环境
- 某进程开始运行前必然要恢复期运行环境
- 将PCB插入合适的队列
- 分配/回收资源
进程通信
进程间通信:
- Inter-Process Communication,IPC,指两个进程之间产生数据交互
- 进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立
- 为了保证安全,一个进程不能直接访问另一个进程的地址空间
共享存储
主存中预留出一块空间,专门用于各个进程的数据共享区,每个进程都可以从共享区中放入/取出数据
- 为避免出错,各个进程对共享空间的访问应该是互斥的。各个进程可使用操作系统内核提供的同步互斥工具(如P、V操作)
- 互斥访问由通信的进程自己负责实现
- 通过"增加页表项/段表项"即可将同一片共享内存区映射到各个进程的地址空间中
Linux 中,如何实现共享内存:
int shm_open(......); //通过 shm_open 系统调用,申请一片共享内存区
void * mmap (......); //通过 mmap 系统调用,将共享内存区映射到进程自己的地址空间
基于数据结构的共享:
- 比如共享空间里只能放一个长度为10的数组。这种共享方式速度慢、限制多,是一种低级通信方式
基于存储区的共享:
- 操作系统在内存中划出一块共享存储区,数据的形式、存放位置都由通信进程控制,而不是操作系统。这种共享方式速度很快,是一种高级通信方式
消息传递
进程间的数据交换以格式化的消息(Message)为单位。进程通过操作系统提供的"发送消息/接收
消息"两个原语进行数据交换
- 格式化信息包括消息头以及消息体两部分
- 消息头包括:发送进程ID、接受进程ID、消息长度等格式化的信息
直接通信方式:
- 消息发送进程要指明接收进程的ID
- 直接通信过程:
- 进程P准备好发送的格式化信息,执行发送原语, send(Q, msg)
- 格式化信息从进程P的地址空间发送,插入进程Q的PCB消息队列中。进程的PCB存放在操作系统内核地址空间中
- 进程Q执行接收原语, receive(P, &msg),从消息队列中的消息读入到进程Q的地址空间,完成通信过程
间接通信方式:
- 通过"信箱"间接地通信。因此又称"信箱通信方式"
- 间接通信过程:
- 进程P准备好发送的格式化信息,执行发送原语, send(A, msg),往信箱A发送消息msg
- 信箱位于操作系统内核地址空间。信箱允许多个进程往同一个信箱send消息,也可以多个进程从同一个信箱中receive消息。消息从进程P的地址空间发送到信箱A的地址空间
- 进程Q执行接收原语, receive(A, &msg),从信箱A接受消息,将信息从信箱A读入到进程Q的地址空间,完成通信过程
管道通信

"管道"是一个特殊的共享文件,又名pipe文件。其实就是在内存中开辟一个大小固定的内存缓冲区
- 管道只能采用半双工通信,某一时间段内只能实现单向的传输。如果要实现双向同时通信,则需要设置两个管道
- 各进程要互斥地访问管道,由操作系统实现
- 当管道写满时,写进程将阻塞,直到读进程将管道中的数据取走,即可唤醒写进程
- 读进程从管道读数据,即便管道没被读空,只要管道没满,写进程就可以往管道写数据
- 当管道读空时,读进程将阻塞,直到写进程往管道中写入数据,即可唤醒读进程
- 写进程往管道写数据,即便管道没被写满,只要管道没空,读进程就可以从管道读数据
- 管道中的数据一旦被读出,就彻底消失
- 因此,当多个进程读同一个管道时,可能会错乱。通常有两种解决方案:
- 一个管道允许多个写进程,一个读进程(2014年408真题高教社官方答案);
- 允许有多个写进程,多个读进程,但系统会让各个读进程轮流从管道中读数据(Linux 的方案)
- 因此,当多个进程读同一个管道时,可能会错乱。通常有两种解决方案:
线程
在没有引进进程之前,系统的各个程序只能串行执行
进程的出现使得程序可以进行并发执行
- 进程是程序的一次执行。但这些功能显然不可能是由一个程序顺序处理就能实现的
- 传统的进程是程序执行流的最小单位
有的进程可能需要"同时"做很多事,而传统的进程只能串行地执行一系列程序。为此,引入了"线程",来增加并发度
- 可以把线程理解为"轻量级进程"
- 引入线程后,线程成为了程序执行流的最小单位
| 影响方面 | 传统进程机制 | 引入线程后 |
|---|---|---|
| 资源分配、调度 | 进程是资源分配、调度的基本单位 | 进程是资源分配的基本单位,线城市调度的基本单位 |
| 并发性 | 只能进程间并发 | 各线程间也能并发,提供了并发度 |
| 系统开销 | 进程间并发,需要切换进程的运行环境,系统开销很大 | 线程间并发,如果是同一进程内线程切换。并发所带来的系统开销减少 |
- 类比以下场景:去图书馆看书。桌子=处理机,人=进程,看不同的书=线程
- 切换进程运行环境:有一个不认识的人要用桌子,你需要你的书收走,他把自己的书放到桌上
- 同一进程内的线程切换=你的舍友要用这张书桌,可以不把桌子上的书收走
线程是一个基本的CPU执行单元,也是程序执行流的最小单位
- 线程时处理及调度的单位
- 多CPU计算机中,各个线程可占用不同的CPU
- 每个线程都有一个线程ID、线程控制块TCB
- 线程也有就绪、阻塞、运行三种基本状态
- 线程几乎不拥有系统资源
- 同个进程的不同线程间共享进程的资源
- 由于共享内存地址空间,同一进程中的线程间通信甚至无需系统干预
- 同一进程的线程切换,不会引起进程的切换
- 不同进程的线程切换,会引起进程切换
- 切换同进程内的线程,系统开销最小
- 切换进程,系统开销较大
线程的实现方式

用户级线程:User-Level Thread, ULT
- 早期的操作系统(如:早期Unix)只支持进程,不支持线程。当时的"线程"是由线程库实现的
- 对于内核态的CPU,操作的最小单元依旧是进程;对于用户态的CPU,开发人员将进程的功能拆分成不同独立的代码段,并通过分时的方式让不同功能并发执行
- 从代码的角度看,线程其实就是一段代码逻辑。不同的代码逻辑上可以看作不同的"线程"。
- while 循环就是一个最弱智的"线程库",线程库完成了对线程的管理工作(如调度)
- 很多编程语言提供了强大的线程库,可以实现线程的创建、销毁、调度等功能
- 用户级线程由应用程序通过线程库实现,所有的线程管理工作都由应用程序负责,包括线程切换
- 用户级线程中,线程切换可以在用户态下即可完成,无需操作系统干预
- 在用户看来,是有多个线程。但是在操作系统内核看来,并意识不到线程的存在。"用户级线程"就是"从用户视角看能看到的线程"
- 优点:
- 用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高
- 缺点:
- 当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可在多核处理机上并行运行

内核级线程:Kernel-Level Thread, KLT, 又称"内核支持的线程"
- 内核级线程是由操作系统支持的线程。大多数现代操作系统都实现了内核级线程,如Windows、Linux
- 内核级线程的管理工作由操作系统内核完成
- 线程调度、切换等工作都由内核负责,因此内核级线程的切换必然需要在核心态下才能完成
- 操作系统会为每个内核级线程建立相应的TCB(Thread Control Block,线程控制块),通过TCB对线程进行管理。"内核级线程"就是"从操作系统内核视角看能看到的线程"
- 优点:
- 当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理机上并行执行
- 缺点:
- 一个用户进程会占用多个内核级线程,线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高,开销大
多线程模型
在支持内核级线程的系统中,根据用户级线程和内核级线程的映射关系,可以划分为几种多线程模型:
- 一对一模型
- 一个用户级线程映射到一个内核级线程。每个用户进程有与用户级线程同数量的内核级线程
- 优点:
- 当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理机上并行执行
- 缺点:
- 一个用户进程会占用多个内核级线程,线程切换由操作系统内核完成,需要切换到核心态,因此线程管理的成本高,开销大
- 多对一模型
- 多个用户级线程映射到一个内核级线程。且一个进程只被分配一个内核级线程
- 操作系统只"看得见"内核级线程,因此只有内核级线程才是处理机分配的单位
- 优点:
- 用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高
- 缺点:
- 当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可在多核处理机上并行运行
- 多对多模型
- n 用户及线程映射到m 个内核级线程(n >= m)。每个用户进程对应m 个内核级线程
- 克服了多对一模型并发度不高的缺点(一个阻塞全体阻塞),又克服了一对一模型中一个用户进程占用太多内核级线程,开销太大的缺点
- 用户级线程是"代码逻辑"的载体,内核级线程是"运行机会"的载体
- 内核级线程才是处理机分配的单位
- 例如:多核CPU环境下,左边这个进程最多能被分配两个核。
- 一段"代码逻辑"只有获得了"运行机会"才能被CPU执行
- 内核级线程中可以运行任意一个有映射关系的用户级线程代码,只有两个内核级线程中正在运行的代码逻辑都阻塞时,这个进程才会阻塞
- 内核级线程才是处理机分配的单位
线程的状态和转换
线程的状态和转换和进程类似

线程使用线程控制块TCB便于操作系统进行管理
- TCB包含以下内容
- 线程标识符TID:类似于PID
- 程序计数器PC的内容:指明线程幕墙执行到哪里
- 其他寄存器的内容:线程运行的中间结果
- 堆栈指针内容:堆栈保存函数调用信息、局部变量等
- 线程运行状态:包括运行、就绪、阻塞
- 优先级:作为吸纳还曾调度、资源分配的参考
- TCB中程序计数器PC、其他寄存器、堆栈指针是线程切换时需要保存和恢复的内容
可将多个线程TCB组织成一个线程表thread table
- 按照不同系统的不同需求,可按照不同线程的状态或者功能归在同一张线程表中,也可直接在进程中将所有所属线程组成一张表
- 线程表的目的就是将同类型的线程归在一起,方便管理。不同系统设计方案各不相同
调度
调度:
- 当有一堆任务要处理,但由于资源有限,这些事情没法同时处理。这就需要确定某种规则来决定处理这些任务的顺序
高级调度:作业调度
- 作业:一个具体的任务
- 用户向系统提交一个作业 ≈ 用户让操作系统启动一个程序 = 操作系统来处理一个具体的任务
- 内存空间有限,有时无法将用户提交的作业全部放入内存,高级调度就是按一定的原则从外存的作业后备队列中挑选一个作业调入内存,并创建进程
- 每个作业只调入一次,调出一次。作业调入时会建立PCB,调出时才撤销PCB
中级调度:内存调度
- 内存不够时,除了调整作业执行顺序外,还可将某些进程的数据调出外存,等内存空闲或者进程需要运行时再重新调入内存
- 终极调度就是按照某种策略决定将哪个处于挂起状态的进程重新调入内存
- 一个进程可能会被多次调出、调入内存,因此中级调度发生的频率要比高级调度更高
低级调度:进程调度/处理机调度
- 按照某种策略从就绪队列中选取一个进程,将处理机分配给该进程
- 进程调度是操作系统中最基本的一种调度,在一般的操作系统中都必须配置进程调度
- 进程调度的频率很高,一般几十ms一次
由于调度的出现,进程的状态除了之前的创建态、就绪态、运行态、阻塞态、终止态以外,还存在挂起态

- 挂起态,suspend:暂时调到外存等待的进程状态为挂起状态
- 挂起态又可以进一步细分为就绪挂起、阻塞挂起两种状态
- "挂起"和"阻塞"两种状态都是暂时不能获得CPU的服务。但挂起态是将进程映像调到外存去了;而阻塞态下进程映像还在内存中
- 有的操作系统会把就绪挂起、阻塞挂起分为两个挂起队列,甚至会根据阻塞原因不同再把阻塞挂起进程进一步细分为多个队列
| 不同层次调度 | 调度含义 | 调度发生位置 | 发生频率 | 对进程状态的影响 |
|---|---|---|---|---|
| 高级调度(作业调度) | 按照某种规则,从后背队列中选择合适的作业将其调入内存,并为其创建进程 | 外存 -> 内存(面向作业) | 最低 | 无 -> 创建态 -> 就绪态 |
| 中级调度(内存调度) | 按照某种规则,从挂起队列中选择合适的进程将其数据调回内存 | 外存 -> 内存(面向作业) | 中等 | 挂起态 -> 就绪态 或 阻塞挂起 -> 阻塞态 |
| 低级调度(进程调度) | 按照某种规则,从就绪队列中选择一个进程为其分配处理机 | 内存 -> CPU | 最高 | 就绪态 -> 运行态 |
调度算法主要研究进程调度方面的问题
进程调度
进程调度(低级调度),就是按照某种算法从就绪队列中选择一个进程为其分配处理机
临界资源:
- 一个时间段内只允许一个进程使用的资源。各进程需要互斥地访问临界资源。
临界区:
- 访问临界资源的那段代码
内核程序临界区:
- 一般是用来访问某种内核数据结构的
- 比如进程的就绪队列(由各就绪进程的PCB组成)
进程调度时机
需要进行进程调度与切换的情况:
- 当前运行的进程主动放弃处理机:
- 进程正常终止
- 运行过程中发生异常而终止
- 进程主动请求阻塞(如等待I/O)
有的系统中只允许进程主动放弃处理机
- 当前运行的进程被动放弃处理机:
- 分给进程的时间片用完
- 有更紧急的事需要处理(如I/O中断)
- 有更高优先级的进程进入就绪队列
有的系统中,进程可以主动放弃处理机,当有更紧急的任务需要处理时,也会强行剥夺处理机(被动放弃)
不能进行进程调度与切换的情况:
- 在处理中断的过程中。中断处理过程复杂,与硬件密切相关,很难做到在中断处理过程中进行进程切换
- 进程在操作系统内核程序临界区中
- 在原子操作过程中(原语)。原子操作不可中断,要一气呵成(如之前讲过的修改PCB中进程状态标志,并把PCB放到相应队列)
进程在操作系统内核程序临界区不能进行调度和切换,但是进程在普通临界区中是可以进行调度、切换的
- 当一个进程处于内核程序临界区时,如访问就绪队列:
- 该进程会将该临界资源进行上锁,只要该进程未退出临界区时,其他进程无法访问该临界资源
- 如果该进程发生了调度,由于进程调度也需要使用就绪队列,但无法访问,因此也无法顺利进行进程调度
- 内核程序临界区访问的临界资源如果不尽快解锁释放,极有可能影响到操作系统内核的其他管理工作,因此在范围跟内核程序临界区期间,不能进行调度和切换
- 当一个进程处于普通程序区时,如访问打印机:
- 该进程会将该临界资源进行上锁,只要该进程未退出临界区时,其他进程无法访问该临界资源
- 但打印机属于慢速设备,如果不允许进程调度的话,会让CPU处于被占用但是空闲等待状态,效率极低
- 普通临界区访问的临界资源不会直接影响到操作系统的内核管理工作,因此进程在访问普通临界区时可以进行调度和切换
进程调度方式
非剥夺调度方式:又称非抢占方式
- 只允许进程主动放弃处理机。在运行过程中即便有更紧迫的任务到达,当前进程依然会继续使用处理机,直到该进程终止或主动要求进入阻塞态
- 实现简单,系统开销小但是无法及时处理紧急任务,适合于早期的批处理系统
剥夺调度方式:又称抢占方式
- 当一个进程正在处理机上执行时,如果有一个更重要或更紧迫的进程需要使用处理机,则立即暂停正在执行的进程,将处理机分配给更重要紧迫的那个进程
- 可以优先处理更紧急的进程,也可实现让各进程按时间片轮流执行的功能(通过时钟中断)。适合于分时操作系统、实时操作系统
进程的切换与过程
狭义的进程调度指的是从就绪队列中选中一个要运行的进程
- 这个进程可以是刚刚被暂停执行的进程,也可能是另一个进程,后一种情况就需要进程切换
- 广义的进程调度包含了选择一个进程和进程切换两个步骤
进程切换是指一个进程让出处理机,由另一个进程占用处理机的过程
- 进程切换的过程主要完成了:
- 对原来运行进程各种数据的保存
- 对新的进程各种数据的恢复
- 如:程序计数器、程序状态字、各种数据寄存器等处理机现场信息,这些信息一般保存在进程控制块
- 进程切换是有代价的,因此如果过于频繁的进行进程调度、切换,必然会使整个系统的效率降低,使系统大部分时间都花在了进程切换上,而真正用于执行进程的时间减少
调度器与闲逛进程
调度器:scheduler,也叫调度程序

- 其中②、③由调度程序引起,并通过调度算法选怎谁线进行调度,分配给各个进程若干时间片进行运行
- 触发调度程序调度的时机:
- 创建新进程
- 进程退出
- 运行进程阻塞
- I/O中断发生,可能还会唤醒
- 非抢占式调度策略,只有运行进程阻塞或退出才触发调度程序工作
- 抢占式调度策略,每个时钟中断或k个时钟中断会触发调度程序工作
调度器对于不支持内核级线程的操作系统,调度程序的处理对象是进程;对于支持内核级线程的操作系统,调度程序的处理对象是内核线程
调度程序永远的备胎,没有其他就绪进程时,运行闲逛进程idle
- 特性:
- 优先级最低
- 一般经常使用0地址指令,占用一个完整的指令周期,指令周期末尾例行检查中断
0地址不需要访存、运算操作,执行速度快
- 能耗低
调度的目标
调度的目的即评价调度算法指标
CPU利用率:
- 由于早期的CPU造价极其昂贵,因此人们会希望让CPU尽可能多地工作,使用CPU利用率来评估执行效率。CPU利用率指CPU "忙碌"的时间占总时间的比例,利用率 = 忙碌的时间/总时间
- 有的题目还会要求计算某种设备的利用率
- 通常会考察多道程序并发执行的情况,可以用"甘特图"来辅助计算
系统吞吐量:
- 对于计算机来说,希望能用尽可能少的时间处理完尽可能多的作业
- 系统吞吐量表示单位时间内完成作业的数量,系统吞吐量 = 总共完成了多少道作业/总共花了多少时间
周转时间:
- 作业被提交给系统开始,到作业完成为止的这段时间间隔
- 周转时间括四个部分:
- 1)作业在外存后备队列上等待作业调度(高级调度)的时间;2)进程在就绪队列上等待进程调度(低级调度)的时间;3)进程在CPU上执行的时间;4)进程等待I/O操作完成的时间
- 后三项在一个作业的整个处理过程中,可能发生多次
- 作业周转时间 = 作业完成时间 – 作业提交时间
- 对于用户来说,更关心自己的单个作业的周转时间
- 平均周转时间 = 各作业周转时间之和/作业数
- 对于操作系统来说,更关心系统的整体表现,因此更关心所有作业周转时间的平均值
- 带权周转时间= 作业周转时间/作业实际运行的时间 = (作业完成时间 – 作业提交时间)/作业实际运行的时间
- 带权周转时间必然 ≥ 1
- 带权周转时间与周转时间都是越小越好
- 平均带权周转时间 = 各作业带权周转时间之和/作业数
对于周转时间相同的两个作业,实际运行时间长的作业在相同时间内被服务的时间更多,带权周转时间更小,用户满意度更高
对于实际运行时间相同的两个作业,周转时间短的带权周转时间更小,用户满意度更高
等待时间:
- 进程/作业处于等待处理机状态时间之和。等待时间越长,用户满意度越低

- 对于进程来说,等待时间就是指进程建立后等待被服务的时间之和,在等待I/O完成的期间其实进程也是在被服务的,所以不计入等待时间
- 对于作业来说,不仅要考虑建立进程后的等待时间,还要加上作业在外存后备队列中等待的时间
- 一个作业总共需要被CPU服务多久,被I/O设备服务多久一般是确定不变的,因此调度算法其实只会影响作业/进程的等待时间。当然,与前面指标类似,也有"平均等待时间"来评价整体性能
响应时间:
- 从用户提交请求到首次产生响应所用的时间
- 对于计算机用户来说,会希望自己的提交的请求(比如通过键盘输入了一个调试命令)尽早地开始被系统服务、回应
调度算法
进程饥饿:
- 某进程/作业长期得不到服务。如果一直得不到服务,则称为"饿死"
先来先服务、短作业优先、高相应比优先算法,一般适合用于早期的批处理系统;而时间片轮转、优先级调度、多级反馈队列算法,适合用于交互式系统
时间片轮转算法常用于分时操作系统,更注重"响应时间",因而一般不计算周转时间
调度算法:先来先服务
先来先服务FCFS, First Come First Serve
- 算法思想:
- 主要从"公平"的角度考虑(类似于我们生活中排队买东西的例子)
- 算法规则:
- 按照作业/进程到达的先后顺序进行服务
- 先来先服务算法,用于作业调度时,考虑的是哪个作业先到达后备队列;用于进程调度时,考虑的是哪个进程先到达就绪队列
- 先来先服务算法是非抢占算法,不会导致进程饥饿
- 优点:
- 公平、算法实现简单
- 缺点:
- 排在长作业(进程)后面的短作业需要等待很长时间,带权周转时间很大,对短作业来说用户体验不好
- 即,FCFS算法对长作业有利,对短作业不利
例题:各进程到达就绪队列的时间、需要的运行时间如下表所示。使用先来先服务调度算法,计算各进程的等待时间、平均等待时间、周转时间、平均周转时间、带权周转时间、平均带权周转时间
| 进程 | 到达时间 | 运行时间 |
|---|---|---|
| P1 | 0 | 7 |
| P2 | 2 | 4 |
| P3 | 4 | 1 |
| P4 | 5 | 4 |
- 先来先服务调度算法:按照到达的先后顺序调度,事实上就是等待时间越久的越优先得到服务。因此,调度顺序为:P1 -> P2 -> P3 -> P4
- 假定P1作业在0时刻开始,则P2在7时刻开始,P3在11时刻开始,P4在11时刻开始,16时刻所有作业运行完成
- 周转时间 = 完成时间- 到达时间
- P1=7-0=7;P2=11-2=9;P3=12-4=8;P4=16-5=11
- 带权周转时间 = 周转时间/运行时间
- P1=7/7=1;P2=9/4=2.25;P3=8/1=8;P4=11/4=2.75
- 等待时间 = 周转时间– 运行时间
- P1=7-7=0;P2=9-4=5;P3=8-1=7;P4=11-4=7
本例中的进程都是纯计算型的进程,一个进程到达后要么在等待,要么在运行。如果是又有计算、又有I/O操作的进程,其等待时间就是周转时间 - 运行时间 - I/O操作的时间
- 平均周转时间 = (7+9+8+11)/4 = 8.75
- 平均带权周转时间 = (1+2.25+8+2.75)/4 = 3.5
- 平均等待时间 = (0+5+7+7)/4 = 4.75
调度算法:短作业优先
短作业优先SJF, Shortest Job First
- 算法思想:
- 追求最少的平均等待时间,最少的平均周转时间、最少的平均平均带权周转时间
- 算法规则:
- 最短的作业/进程优先得到服务(所谓"最短",是指要求服务时间最短)
- 短作业优先算法即可用于作业调度,也可用于进程调度。用于进程调度时称为"短进程优先算法",SPF, Shortest Process First
- SJF、SPF是非抢占式算法,最短剩余时间优先算法SRTN, Shortest Remaining Time Next是非抢占式算法
- 短作业优先算法回导致饥饿现象
- 如果源源不断地有短作业/进程到来,可能使长作业/进程长时间得不到服务,产生"饥饿"现象
- 优点:
- "最短的"平均等待时间、平均周转时间
- 缺点:
- 不公平。对短作业有利,对长作业不利。可能产生饥饿现象。另外,作业/进程的运行时间是由用户提供的,并不一定真实,不一定能做到真正的短作业优先
例题:进程到达就绪队列的时间、需要的运行时间如下表所示。使用非抢占式的短作业优先调度SPF算法,计算各进程的等待时间、平均等待时间、周转时间、平均周转时间、带权周转时间、平均带权周转时间
| 进程 | 到达时间 | 运行时间 |
|---|---|---|
| P1 | 0 | 7 |
| P2 | 2 | 4 |
| P3 | 4 | 1 |
| P4 | 5 | 4 |
- 短作业/进程优先调度算法:每次调度时选择当前已到达且运行时间最短的作业/进程。因此,调度顺序为:P1 -> P3 -> P2 -> P4
- 假定P1作业在0时刻开始,则P3在7时刻开始,P2在8时刻开始,P4在12时刻开始,16时刻所有作业运行完成
- 周转时间 = 完成时间- 到达时间:
- P1=7-0=7;P3=8-4=4;P2=12-2=10;P4=16-5=11
- 带权周转时间 = 周转时间/运行时间:
- P1=7/7=1;P3=4/1=4;P2=10/4=2.5;P4=11/4=2.75
- 等待时间 = 周转时间– 运行时间:
- P1=7-7=0;P3=4-1=3;P2=10-4=6;P4=11-4=7
- 平均周转时间 = (7+4+10+11)/4 = 8
- 平均带权周转时间 = (1+4+2.5+2.75)/4 = 2.56
- 平均等待时间 = (0+3+6+7)/4 = 4
对比FCFS算法的结果,显然SPF算法的平均等待/周转/带权周转时间都要更低
抢占式的短作业优先调度算法,计算各进程的等待时间、平均等待时间、周转时间、平均周转时间、带权周转时间、平均带权周转时间
| 进程 | 到达时间 | 运行时间 |
|---|---|---|
| P1 | 0 | 7 |
| P2 | 2 | 4 |
| P3 | 4 | 1 |
| P4 | 5 | 4 |
- 最短剩余时间优先算法SRTN:每当有进程加入就绪队列改变时就需要调度,如果新到达的进程剩余时间比当前运行的进程剩余时间更短,则由新进程抢占处理机,当前运行进程重新回到就绪队列。另外,当一个进程完成时也需要调度
- 假定P1作业在0时刻开始,执行到2时刻,P2进入就绪队列,抢占调度,执行到4时刻
- 4时刻P3进入就绪队列,P3抢占调度,执行到5时刻
- P3执行完成,5时刻P4进入就绪队列,P2抢占调度,执行到7时刻
- P2执行完成,P4抢占调度,执行到11时刻
- P4执行完成,P1抢占调度,执行到16时刻,P1执行完成
- 周转时间 = 完成时间- 到达时间
- P1=16-0=16;P2=7-2=5;P3=5-4=1;P4=11-5=6
- 带权周转时间 = 周转时间/运行时间
- P1=16/7=2.28;P2=5/4=1.25;P3=1/1=1;P4=6/4=1.5
- 等待时间 = 周转时间– 运行时间
- P1=16-7=9;P2=5-4=1;P3=1-1=0;P4=6-4=2
- 平均周转时间 = (16+5+1+6)/4 = 7
- 平均带权周转时间 = (2.28+1.25+1+1.5)/4 = 1.50
- 平均等待时间 = (9+1+0+2)/4 = 3
对比非抢占式的短作业优先算法,显然抢占式的这几个指标又要更低
备注:
- 未特别说明,所提到的"短作业/进程优先算法"默认是非抢占式的
- 在所有进程同时可运行或几乎同时达到时,采用SJF调度算法的平均等待时间、平均周转时间最少
- 如果不强调同时达到,则抢占式的短作业/进程优先调度算法(最短剩余时间优先, SRNT算法)的平均等待时间、平均周转时间才是最少的
如果选择题中遇到"SJF 算法的平均等待时间、平均周转时间最少"的选项,那最好判断其他选项是不是有很明显的错误,如果没有更合适的选项,那也应该选择该选项
调度算法:高相应比优先
高响应比优先HRRN, Highest Response Ratio Next
- 算法思想:
- 综合考虑作业/进程的等待时间和要求服务的时间
- 算法规则:
- 在每次调度时先计算各个作业/进程的响应比,选择响应比最高的作业/进程为其服务
- 响应比= (等待时间 + 要求服务时间)/要求服务时间,一般响应比 ≥ 1
- 高相应比算法既可用于作业调度,也可用于进程调度
- 高相应比算法是非抢占式的算法,不会造成饥饿
- 因此只有当前运行的作业/进程主动放弃处理机时,才需要调度,才需要计算响应比
- 优点:
- 综合考虑了等待时间和运行时间(要求服务时间)等待时间相同时,要求服务时间短的优先(SJF 的优点)要求服务时间相同时,等待时间长的优先(FCFS 的优点)
- 对于长作业来说,随着等待时间越来越久,其响应比也会越来越大,从而避免了长作业饥饿的问题
例题:各进程到达就绪队列的时间、需要的运行时间如下表所示。使用高响应比优先调度算法,计算各进程的等待时间、平均等待时间、周转时间、平均周转时间、带权周转时间、平均带权周转时
| 进程 | 到达时间 | 运行时间 |
|---|---|---|
| P1 | 0 | 7 |
| P2 | 2 | 4 |
| P3 | 4 | 1 |
| P4 | 5 | 4 |
- 高响应比优先算法:非抢占式的调度算法,只有当前运行的进程主动放弃CPU时(正常/异常完成,或主动阻塞),才需要进行调度,调度时计算所有就绪进程的响应比,选响应比最高的进程上处理机
- 0时刻:只有P1到达就绪队列,P1上处理机
- 7时刻(P1主动放弃CPU):就绪队列中有P2(响应比=(5+4)/4=2.25)、P3((3+1)/1=4)、P4((2+4)/4=1.5),
- P2和P4要求服务时间一样,但P2等待时间长,所以必然是P2响应比更大
- 8时刻(P3完成):P2(2.5)、P4(1.75)
- 12时刻(P2完成):就绪队列中只剩下P
调度算法:时间片轮转
时间片轮转RR,Round-Robin
- 算法思想:
- 公平地、轮流地为各个进程服务,让每个进程在一定时间间隔内都可以得到响应
- 算法规则:
- 按照各进程到达就绪队列的顺序,轮流让各个进程执行一个时间片(如100ms)。若进程未在一个时间片内执行完,则剥夺处理机,将进程重新放到就绪队列队尾重新排队
- 用于进程调度(只有作业放入内存建立了相应的进程后,才能被分配处理机时间片)
- 时间片轮转调度算法属于抢占式的算法,不会造成饥饿
- 若进程未能在时间片内运行完,将被强行剥夺处理机使用权,由时钟装置发出时钟中断来通知CPU时间片已到
- 优点:
- 公平;响应快,适用于分时操作系统;
- 缺点:
- 由于高频率的进程切换,因此有一定开销;不区分任务的紧急程度
例题:各进程到达就绪队列的时间、需要的运行时间如下表所示。使用时间片轮转调度算法,分析时间片大小分别是2、5时的进程运行情况
| 进程 | 到达时间 | 运行时间 |
|---|---|---|
| P1 | 0 | 5 |
| P2 | 2 | 4 |
| P3 | 4 | 1 |
| P4 | 5 | 6 |
- 假设时间片大小为5,时间片轮转调度算法轮流让就绪队列中的进程依次执行一个时间片(每次选择的都是排在就绪队列队头的进程)
- 0时刻(P1(5) ):只有P1到达,P1上处理机。
- 2时刻(P2(4)):P2到达,但P1时间片尚未结束,因此暂不调度
- 4时刻(P2(4) -> P3(1)):P3到达,但P1时间片尚未结束,因此暂不调度
- 5时刻(P2(4) -> P3(1) -> P4(6) ):P4到达,同时,P1运行结束。发生调度,P2上处理机
- 9时刻(P3(1) -> P4(6) ):P2运行结束,虽然时间片没用完,但是会主动放弃处理机。发生调度。
- 10时刻(P4(6) ):P3运行结束,虽然时间片没用完,但是会主动放弃处理机。发生调度。
- 15时刻():P4时间片用完,但就绪队列为空,因此会让P4继续执行一个时间片。
- 16时刻():P4运行完,主动放弃处理机。所有进程运行完。
关于时间片大小的选择:
- 如果时间片太大,使得每个进程都可以在一个时间片内就完成,则时间片轮转调度算法退化为先来先服务调度算法,并且会增大进程响应时间。因此时间片不能太大
- 另一方面,进程调度、切换是有时间代价的(保存、恢复运行环境),因此如果时间片太小,会导致进程切换过于频繁,系统会花大量的时间来处理进程切换,从而导致实际用于进程执行的时间比例减少。可见时间片也不能太小
- 比如:系统中有10个进程在并发执行,如果时间片为1秒,则一个进程被响应可能需要等9秒...
- 也就是说,如果用户在自己进程的时间片外通过键盘发出调试命令,可能需要等待9秒才能被系统响应
- 一般来说,设计时间片时要让切换进程的开销占比不超过1%
调度算法:优先级
优先级调度算法
- 算法思想:
- 随着计算机的发展,特别是实时操作系统的出现,越来越多的应用场景需要根据任务的紧急程度来决定处理顺序
- 算法规则:
- 每个作业/进程有各自的优先级,调度时选择优先级最高的作业/进程
- 既可用于作业调度,也可用于进程调度。甚至,还会用于I/O调度中
- 优先级调度算法抢占式、非抢占式都有,进程也存在饥饿现象
- 做题时的区别在于:非抢占式只需在进程主动放弃处理机时进行调度即可,而抢占式还需在就绪队列变化时,检查是否会发生抢占
- 优点:
- 用优先级区分紧急程度、重要程度,适用于实时操作系统。可灵活地调整对各种作业/进程的偏好程度
- 缺点:
- 若源源不断地有高优先级进程到来,则可能导致饥饿
例题:各进程到达就绪队列的时间、需要的运行时间、进程优先数如下表所示。使用非抢占式的优先级调度算法,分析进程运行情况。(注:优先数越大,优先级越高)
| 进程 | 到达时间 | 运行时间 | 优先数 |
|---|---|---|---|
| P1 | 0 | 7 | 1 |
| P2 | 2 | 4 | 2 |
| P3 | 4 | 1 | 3 |
| P4 | 5 | 4 | 2 |
- 假设时间片大小为5,时间片轮转调度算法轮流让就绪队列中的进程依次执行一个时间片(每次选择的都是排在就绪队列队头的进程)
- 0时刻(P1):只有P1到达,P1上处理机。
- 7时刻(P2、P3、P4):P1运行完成主动放弃处理机,其余进程都已到达,P3优先级最高,P3上处理机。
- 8时刻(P2、P4 ):P3完成,P2、P4优先级相同,由于P2先到达,因此P2优先上处理机
- 12时刻(P4):P2完成,就绪队列只剩P4,P4上处理机。
- 16时刻():P4完成,所有进程都结束
括号内表示当前处于就绪队列的进程
各进程到达就绪队列的时间、需要的运行时间、进程优先数如下表所示。使用抢占式的优先级调度算法,分析进程运行情况。(注:优先数越大,优先级越高)
| 进程 | 到达时间 | 运行时间 | 优先数 |
|---|---|---|---|
| P1 | 0 | 7 | 1 |
| P2 | 2 | 4 | 2 |
| P3 | 4 | 1 | 3 |
| P4 | 5 | 4 | 2 |
- 0时刻(P1):只有P1到达,P1上处理机。
- 2时刻(P2):P2到达就绪队列,优先级比P1更高,发生抢占。P1回到就绪队列,P2上处理机。
- 4时刻(P1、P3):P3到达,优先级比P2更高,P2回到就绪队列,P3抢占处理机。
- 5时刻(P1、P2、P4):P3完成,主动释放处理机,同时,P4也到达,由于P2比P4更先进入就绪队列,因此选择P2上处理机
- 7时刻(P1、P4):P2完成,就绪队列只剩P1、P4,P4上处理机。
- 11时刻(P1 ):P4完成,P1上处理机
- 16时刻():P1完成,所有进程均完成
关于优先级的设定:
- 就绪队列未必只有一个,可以按照不同优先级来组织。另外,也可以把优先级
高的进程排在更靠近队头的位置根据优先级是否可以动态改变,可将优先级分为静态优先级和动态优先级两种。- 静态优先级:创建进程时确定,之后一直不变。
- 动态优先级:创建进程时有一个初始值,之后会根据情况动态地调整优先级
- 通常,系统进程优先级高于用户进程;前台进程优先级高于后台进程;操作系统更偏好I/O型进程(或称I/O繁忙型进程)
- 与I/O型进程相对的是计算型进程(或称CPU繁忙型进程)
- I/O设备和CPU可以并行工作。如果优先让I/O繁忙型进程优先运行的话,则越有可能让I/O设备尽早地投入工作,则资源利用率、系统吞吐量都会得到提升
对于动态优先级的动态调整,从追求公平、提升资源利用率等角度考虑
- 如果某进程在就绪队列中等待了很长时间,则可以适当提升其优先级
- 如果某进程占用处理机运行了很长时间,则可适当降低其优先级
- 如果发现一个进程频繁地进行I/O操作,则可适当提升其优先级
调度算法:多级反馈队列
多级反馈队列调度算法
- 算法思想:
- 对其他调度算法的折中权衡
- 算法规则:
- 设置多级就绪队列,各级队列优先级从高到低,时间片从小到大
- 新进程到达时先进入第1级队列,按FCFS原则排队等待被分配时间片,若用完时间片进程还未结束,则进程进入下一级队列队尾。如果此时已经是在最下级的队列,则重新放回该队列队尾
- 只有第k 级队列为空时,才会为k+1 级队头的进程分配时间片
- 主要用于进程调度
- 抢占式的算法,进程也存在饥饿现象
- k 级队列的进程运行过程中,若更上级的队列(1~k-1级)中进入了一个新进程,则由于新进程处于优先级更高的队列中,因此新进程会抢占处理机,原来运行的进程放回k 级队列队尾
- 优点:
- 对各类型进程相对公平(FCFS的优点)
- 每个新到达的进程都可以很快就得到响应(RR的优点)
- 短进程只用较少的时间就可完成(SPF的优点)
- 不必实现估计进程的运行时间(避免用户作假)
- 可灵活地调整对各类进程的偏好程度,比如CPU密集型进程、I/O密集型进程
- 可以将因I/O而阻塞的进程重新放回原队列,这样I/O型进程就可以保持较高优先级
例题:各进程到达就绪队列的时间、需要的运行时间如下表所示。使用多级反馈队列调度算法,分析进程运行的过程
| 进程 | 到达时间 | 运行时间 |
|---|---|---|
| P1 | 0 | 8 |
| P2 | 1 | 4 |
| P3 | 5 | 1 |
- 设置多级就绪队列,各级队列优先级从高到低,时间片从小到大

- 新进程到达时先进入第1级队列,按FCFS原则排队等待被分配时间片。若用完时间片进程还未结束,则进程进入下一级队列队尾。如果此时已经在最下级的队列,则重新放回最下级队列队尾
- 只有第k 级队列为空时,才会为k+1 级队头的进程分配时间片被抢占处理机的进程重新放回原队列队尾
- 执行顺序为:P1(1) —> P2(1) —> P1(2) —> P2(1) —> P3(1) —> P2(2) —> P1(4) —> P1(1)
- 假定P1在0时刻进入第1级队列,拥有1个时间片,结束后进入第2级队列的队尾
- 1时刻,P2进入第1级队列。由于第1级队列非空,第1级队列进程优先调度,P2也拥有1个时间片,结束后也进入第2级队列的队尾
- 2时刻,此时只有第2级队列非空,则队首P1出队进行调度,拥有2个时间片,结束后进入第3级队列的队尾
- 4时刻,第2级队列非空,第2级队列优先调度,P2拥有2个时间片。执行到5时刻P3进入第1级队列,调度被P3抢占,P2回到第2级队列
- 5时刻,第1级队列非空,P3拥有1个时间片,直到6时刻,P3执行完成
- 6时刻,第2级队列非空,P2拥有2个时间片,直至8时刻,P2执行完成
- 8时刻,第3队列非空,P1拥有4个时间片,直至12时刻,P1执行完成
调度算法:多级队列调度
多级队列调度算法:

- 系统中按进程类型设置多个队列,进程创建成功后插入某个队列
- 队列之间可采取固定优先级,或时间片划分
- 固定优先级:高优先级空时低优先级进程才能被调度
- 时间片划分:如三个队列分配时间50%、40%、10%
- 各队列可采用不同的调度策略,如:
- 系统进程队列采用优先级调度
- 交互式队列采用RR
- 批处理队列采用FCFS
本文来自博客园,作者:GK_Jerry,转载请注明原文链接:https://www.cnblogs.com/GKJerry/articles/18379909

浙公网安备 33010602011771号