第二章--处理机管理

井底之蛙,不知大海之宽阔,却知晓天空之蓝。

进程

  • 程序:是静态的,就是个存放在磁盘里的可执行文件,是一系列的指令集合。
  • 进程:是动态的,是程序的一次执行过程。

进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。

1761288519157

当进程被创建时,操作系统会为该进程分配一个唯一的、不重复的身份证号——PID(Process ID,进程ID)。

除此之外,操作系统还会记录进程的以下信息:

  • 分配了哪些资源
    • 内存
    • I/O设备
    • 文件
  • 进程的运行情况
    • CPU时间
    • 磁盘使用情况
    • 网络流量

关于一个进程的所有信息都被保存在一个数据结构PCB(Process Control Block)中,即进程控制块。PCB是进程存在的唯一标志。

当一个进程被创建时,操作系统就会为其创建PCB,当进程结束时,会回收PCB。

进程实体

进程实体 = 进程PCB + 程序段 + 数据段

  • 进程实体:进程在某一时刻的状态。
  • PCB:存储进程的信息。
  • 程序段:程序执行的指令。
  • 数据段:在程序运行过程中产生的各种数据。

进程的特征

  • 动态性:进程是程序的一次执行过程,是动态地产生、变化和消亡的。
  • 并发性:内存中有多个进程实体,各进程可并发执行。
  • 独立性:进程是能独立运行、独立获得资源、独立接受调度的基本单位。
  • 异步性:各进程按各自独立的、不可预知的速度向前推进,操作系统要提供进程同步机制,来解决异步问题。
  • 结构性:每个进程都会配备一个PCB。结构上看,进程由程序段、数据段、PCB组成。

进程的状态

创建态

  • 进程正在被创建时,它的状态就是创建态,在这个阶段操作系统会为进程分配资源、初始化PCB。

就绪态

  • 当进程创建完成后,便进入就绪态,处于就绪状态的进程已经具备运行条件,但由于没有空闲的CPU,就暂时不能运行。

运行态

  • 如果一个进程此时在CPU运行,那么这个进程就处于运行态。

阻塞态

  • 在进程运行过程中,可能会请求等待某个事件的发送,在这个事件发生之前,进程无法继续往下执行。
  • 此时操作系统会让这个进程下CPU,并让他进入阻塞态
  • 当事件发生后,进程从阻塞态进入就绪态

    一个进程因什么事情而阻塞,就因什么事情而唤醒。

终止态

  • 一个进程可以执行exit系统调用,请求操作系统终止该进程。此时该进程会进入终止态。
  • 操作系统会让该进程下CPU,并回收内存空间等资源,最后还要回收该进程的PCB。

1761354282094

在进程PCB中,会有一个变量state来表示进程当前的状态。

进程的组织

链接方式

1761354464069

索引方式

1761354511637

进程控制

进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能。

进程控制程序需要使用原语来实现。一气呵成,不可中断。

原语的执行具有原子性,即执行过程只能一气呵成,期间不允许被中断。

可以用”关中断”和”开中断”这两个特权指令实现原子性。

  • 关中断:CPU在执行完一条指令后,不再检查是否有中断信号。
  • 开中断:恢复检查中断。

进程创建->创建原语

  1. 申请空白PCB
  2. 为新进程分配所需资源
  3. 初始化PCB
  4. 将PCB插入就绪队列

进程结束->撤销原语

  1. 从PCB集合中找到终止进程的PCB
  2. 若进程正在运行,立即剥夺CPU,将CPU分配给其他进程。
  3. 终止所有子进程
  4. 将该进程拥有的所有资源归还给父进程或操作系统
  5. 删除PCB

进程阻塞->阻塞原语

  1. 找到要阻塞的进程对应的PCB
  2. 保护进程运行现场,将PCB状态信息设置为阻塞态,暂时停止进程运行。
  3. 将PCB插入相应事件的等待队列。

进程唤醒->唤醒原语

  1. 在事件等待队列中找到PCB。
  2. 将PCB从等待队列移除,设置进程为就绪状态。
  3. 将PCB插入就绪队列,等待被调度。

进程切换->切换原语

  1. 将进程的运行环境信息存入PCB
  2. PCB移入相应的队列
  3. 选择另一个进程执行,并更新PCB
  4. 根据PCB恢复新进程所需的运行环境

上面过程中提到的:保存现场、恢复环境等概念,指的都是保存当前线程中CPU各种寄存器以及堆栈的状态。

进程通信

进程通信(Inter-Process Communication, IPC)是指两个进程之间产生交互数据。

进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立

为保证安全,一个进程不能直接访问另一个进程的地址空间

共享存储

1761375241559

想要分享数据的进程,可以向操作系统申请一块共享存储区,多个进程可以在共享存储区中交互数据。

为避免出错,各个进程对共享空间的访问应该是互斥的。

各个进程可以使用操作系统内核提供的同步互斥工具

分享方式:

  1. 基于数据结构的共享:

    1761375560251

    • 比如共享空间中只能放一个长度为10的数组。
    • 这种共享方式速度很慢、限制多,是一种低级通信方式。
  2. 基于存储区的共享:

    1761375693367

    • 操作系统在内存中划出一块共享存储区,数据的形式、存放位置都由进程控制,而不是操作系统。
    • 这种共享方式速度很快,是一种高级通信方式。

消息传递

进程间的数据交换以格式化的消息(Message)为单位。进程通过操作系统提供的”发送消息/接收消息”两个原语进行数据交换。

格式化的消息:1761376020414

直接通信方式:消息发送进程要指明接收进程的ID。

1761376553436

间接通信方式:通过”信箱”间接地通信。因此又称”信箱通信方式”。

1761376512500

多个进程可以向同一个信箱中发送消息,也可以从同一个信箱中接收消息。

管道通信

1761376776916

管道:是一个特殊的共享文件,又名pipe文件。其实就是在内存中开辟一个大小固定的内存缓冲区。

管道类似于一个数据结构循环****队列,进程P负责向队列中 offer数据,而进程Q中负责 poll数据。

  • 管道只能采用半双工通信,某一时间段内只能实现单项传输。如果要实现双向同时通信,则需要设置两个管道。
  • 各进程要互斥的访问管道
  • 当管道写满时,写进程将互斥,直到读取进程将管道中的数据取走,即可唤醒写进程。
  • 当管道读空时,读进程将阻塞,直到写进程往管道中写入数据,即可唤醒读进程。
  • 管道权限:
    1. 一个管道允许多个写进程,一个读进程。
    2. 允许多个写进程,多个读进程,但系统会让各个读取进程轮流从管道中读取数据。

信号

区分信号与信号量:

  • 信号量(Semaphore):实现进程间的同步、互斥
  • 信号(Signal):实现进程间通信(IPC)。

信号:用于通知进程某个特定事件已经发生。进程收到一个信号后,对该信号进行处理。

实现原理

在进程的PCB中,一个待处理信号表和被阻塞信号表

待处理信号表(pending):表示接收的信号但是还未处理。

被阻塞信号表(blocked):表示屏蔽的信号,置为1则屏蔽该信号。也称为信号掩码(signal mask)。

1761440670032

需要发送信号的进程可以使用 kill函数:

1
2
//用于发送信号的函数
int kill(pid_t pid, int sig);
  • 接收信号的进程无法知道是谁发送的信号。
  • 重复接收的信号会被丢弃。

信号的处理

时机:

  • 当进程从内核态转为用户态时,例行检查是否有待处理的信号,如果有,就处理信号。

1761441374492

信号的处理

操作系统为每个信号设置了默认的信号处理程序。(一些信号默认忽略,不做处理)

执行进程可以为信号设置用户自定义的信号处理逻辑。(自定义的信号处理程序将覆盖默认处理程序)。

特点:

  • 信号处理程序运行结束后,通常会返回进程的下一条指令继续执行(除非信号处理程序将进程阻塞或终止)。
  • 一旦处理了某个信号,就将pending位重置为0。
  • 重复收到的同类信号,将被简单的丢弃。
  • 当同时收到多个不同类信号时,通常先处理序列号更小的信号。
  • 有些信号不能被自定义,如Linux中的SIGKILL,SIGSTOP等。

线程

线程也被称为轻量级进程(LWP)。

有些进程可能需要同时做很对事情,而传统的进程只能串行的执行一系列程序。为例,引入了线程,来增加进程的并发度。

1761442782199

引入线程后,线程是基本的CPU执行单元,是程序执行流的最小单位

进程与线程的资源分配

  • 进程:资源分配的基本单位(代码段、数据段、地址空间)。
  • 线程:CPU调度的基本单位。
    • 私有数据:堆栈、寄存器组、线程专用存储。
  • 一个进程的所有线程,共享该进程的资源。

进程与线程的并发性

  • 进程间可以并发执行
  • 线程间也可以并发执行

系统开销:

  • 切换进程,需要切换运行环境,开销大
  • 统一进程下的线程切换,不需要切换进程环境,开销小

1761443417397

线程的实现方式

用户级线程(User-Level Thread, UTL)

早期的操作系统(如:早期Unix)只支持进程,不支持线程。当时的”线程”是由线程库实现的。

只有用户可以感受到线程的存在,操作系统感受不到线程的存在。

1761443913883

最简单的线程库示例:

1
2
3
4
5
6
7
8
9
int main() {
int i = 0;
while (true) {
if (i == 0) { 处理视频聊天的代码; }
if (i == 1) { 处理文字聊天的代码; }
if (i == 2) { 处理文件传输的代码; }
i = (i + 1) % 3; // i 的值为 0,1,2,0,1,2...
}
}

手动将进程的运行再次分为三个时间片,来运行不同的代码逻辑。可以看作有三个线程。

优点

  • 用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高。

缺点

  • 当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可再多核处理机上并行运行。

内核级线程

内核级线程(kernel-Level Thread, KTL),由操作系统支持的线程。

1761444700492

优点

  • 当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理器上并行执行

缺点

  • 一个用户进程会占用多个内核级线程,线程切换由操作系统内核完成,需要切换到核心态,因此线程管理成功太高,开销大。

多线程模型

在支持内核级线程的系统中,根据用户级线程和内核级线程的映射关系,可以划分为几种多线程模型。

一对一模型

一个用户级线程映射到一个内核级线程。每个用户进程有与用户级线程同数量的内核级线程。

1761445463225

优点

  • 当一个线程被阻塞后,别的线程还可以继续执行,并发能力强。多线程可在多核处理器上并行执行

缺点

  • 一个用户进程会占用多个内核级线程,线程切换由操作系统内核完成,需要切换到核心态,因此线程管理成功太高,开销大。

多对一模型

多个用户级线程映射到一个内核级线程,且一个进程只被分配一个内核级线程。

1761445613426

优点

  • 用户级线程的切换在用户空间即可完成,不需要切换到核心态,线程管理的系统开销小,效率高。

缺点

  • 当一个用户级线程被阻塞后,整个进程都会被阻塞,并发度不高。多个线程不可在多核处理机上并行运行。

操作系统此时只能看见内核级线程,因此只有内核级线程才是CPU分配的基本单位。

多对多模型

n个用户级线程映射到m个内核级线程(n >= m)。每个用户进程对应m个内核级线程。

1761446071026

用户级线程是”代码逻辑“的载体。
内核级线程是”运行机会“的载体。

一段”代码逻辑”只有获得了”运行机会”才能被CPU执行。

内核级线程才是CPU分配的单位。

线程的状态与转换

1761446438944

组织与控制

组织管理线程的数据结构:TCB(线程控制块)和线程表(thread table)

1761446826436

处理机调度

当有一堆任务要处理,但由于资源有限,这些事情没法同时处理。这就需要确定某种规则来决定处理这些任务的顺序,这就是”调度”研究的问题。

调度的三个层次

高级调度(作业调度)

作业:一个具体的任务。

用户向系统提交了一个作业 = 用户让操作系统启动一个程序。(处理一个具体的任务)。

高级调度(作业调度):按一定的原则从外存的作业后备队列中挑选一个作业调入内存,并创建进程。**每个作业只调入一次,调出一次。**作业调入时会建立PCB,调出时才撤销PCB。

1761462194287

低级调度(进程调度/处理机调度)

低级调度:按照某种策略从就绪队列中选取一个进程,将处理器分配给它。

低级调度是操作系统中最基本的一种调度调用频率很高,在一般的操作系统中都必须配置低级调度。

1761462317793

中级调度(内存调度)

内存不够时,可能将某些进程的数据调出外存。当内存空间空闲或者进程需要运行时再重新调入内存。

暂时调到外存等待的进程状态为挂起状态(suspend)。被挂起的进程PCB会被组织成挂起队列

中级调度:按照某种策略决定将哪个处于挂起状态的进程重新调入内存。

一个进程可能会被多次调出、调入内存,因此中级调度发送的频率要比高级调度更高。

1761462844171

七状态模型

挂起状态可以进一步细分为:就绪挂起阻塞挂起两种状态。

1761463092419

三层调度

调度类型 要做什么 调度发生在… 发生频率 对进程状态的影响
高级调度 (作业调度) 按照某种规则,从后备队列中选择合适的作业将其调入内存,并为其创建进程 外存$\rightarrow$ 内存 (面向作业) 最低 无$\rightarrow$ 创建态 $\rightarrow$ 就绪态
中级调度 (内存调度) 按照某种规则,从挂起队列中选择合适的进程将其数据调回内存 外存$\rightarrow$ 内存 (面向进程) 中等 挂起态$\rightarrow$ 就绪态 (阻塞挂起 $\rightarrow$ 阻塞态)
低级调度 (进程调度) 按照某种规则,从就绪队列中选择一个进程为其分配处理器 内存$\rightarrow$ CPU 最高 就绪态$\rightarrow$ 运行态

时机、方式、切换与过程

进程调度的时机

需要进行进程调度与切换的情况:

  • 进程主动放弃CPU

    • 正常终止
    • 异常终止
    • 进程主动请求阻塞
  • 进程被迫放弃CPU

    • 分给进程的时间片用完
    • 有更紧急的事情处理
    • 有更高优先级的进程进入队列

不能进行进程调度的情况:

  • 在处理中断的过程中
  • 在原子操作过程中
  • 进程在操作系统内核程序临界区

临界资源:一个时间段内只允许一个进程使用的资源。各进程需要互斥访问临界资源。

临界区:访问临界资源的代码。

解释

  1. 访问内核程序临界区时,由于内核程序的特殊性,不会对内核程序临界区中的代码进行进程调度。希望让进程快点结束对于内核程序的访问。
  2. 访问其他临界区,如打印机等设备时,反而会进行进程调度,因为打印机是慢速资源,可以进程调度防止CPU空转。

进程调度的方式

非剥夺调度方式(非抢占方式):

  • 只允许进程主动放弃处理机。在运行过程中即便有更紧迫的任务到达,当前进程依然会继续使用处理机,直到该进程终止或主动要求进入阻塞态。

剥夺调度方式(抢占方式):

  • 当一个进程正在处理机上执行时,如果有一个更重要或更紧迫的进程需要使用处理机,则立即暂停正在执行的进程,将处理机分配给更重要紧迫的那个进程

进程的切换与过程

进程切换:一个进程让出处理机,由另一个进程占用处理机的过程。

主要过程:

  1. 对原来运行进程各种数据的保存。
  2. 对新的进程各种数据的恢复。

进程的恢复包括:程序计数器、程序状态字、各种数据寄存器等。这些信息存储在进程控制块PCB中

进程的切换是有代价的,因此过于频繁的进行进程调度、切换,必然会导致整个系统的效率降低,使系统大部分事件都花在了进程切换上,而真正用于执行进程的时间减少。

调度器/调度程序(scheduler)

1761530733162

过程2,3由调度程序引起,调度程序决定:

  1. 让哪个进程运行。——调度算法
  2. 运行多长时间。——时间片大小

调度时机

  • 创建新进程
  • 进程退出
  • 运行进程阻塞
  • I/O中断发送(唤醒某些阻塞的进程)

非抢占式调度策略:只有运行进程阻塞退出才触发调度程序工作。

抢占式调度策略每个时钟中断或K个时钟中断会触发调度程序工作。

对于支持内核级线程的操作系统,调度的基本单位是线程

闲逛进程

闲逛进程(idle Process):是操作系统中的一个特殊进程,当系统中没有其他可运行的进程时,由调度器安排它运行,用来占住CPU,防止CPU处于不可控的空转状态。它通常优先级最低,只在系统完全空闲时才执行。

特性:

  • 优先级最低
  • 可以是0地址指令,占一个完整的指令周期。(指令周期末尾例行检查中断)
  • 能耗低。

调度算法的评价指标

利用率

CPU利用率:CPU忙碌的时间占总时间的比例。

$$
\text{利用率} = \frac{\text{忙碌的时间}}{\text{总时间}}
$$

例题:

1761532143505

系统吞吐量

系统吞吐量:单位时间内完成作业的数量。

$$
\text{系统吞吐量} = \frac{\text{完成作业数量}}{\text{总时间}}
$$

1761532301892

周转时间

周转时间:指从作业被提交给系统开始到作业完成为止的这段时间间隔。

$$
周转时间 = 作业完成总时间 - 作业提交时间
$$

平均周转时间

$$
\text{平均周转时间} = \frac{\text{各作业周转时间之和}}{\text{作业数}}
$$

带权周转时间:对于周转时间相同的作业,实际运行时间长的作业在相同时间内被服务的时间更多,带权周转时间更小,用户满意度更高。

$$
\text{带权周转时间} = \frac{\text{作业周转时间}}{\text{作业实际运行的时间}}
$$

平均带权周转时间

$$
\text{平均带权周转时间} = \frac{\text{各作业带权周转时间之和}}{\text{作业数}}
$$

等待时间

等待时间:指进程/作业处于等待处理机的状态时间之和,等待时间越长,用户满意度越低。

等待I/O完成期间进程也算是在被服务,所以不计入等待时间。

其实进程等待时间就是进程生命周期在就绪状态的时间段之和

响应时间

响应时间:指从用户提交请求到首次产生响应所用的时间。

响应时间是到开始响应的时间,而非到相应输出完成的时间,假设线程一提交就被CPU调度,则它的响应时间如下:

1762845073849

调度算法

饥饿:某个进程/作业长时间得不到服务

批处理系统调度算法

先来先服务(FCFS)

先来先服务(First Come First Serve)

等待越久的服务越先得到服务

  • 算法思想:主要从公平的角度考虑
  • 算法规则:按照作业/进程到达的先后顺序进行服务。
  • 调度
    • 作业调度:考虑哪个作业先到达后备队列。
    • 进程调度:考虑哪个进程先到达就绪队列。
  • 是否抢占:非抢占算法。
  • 优点:公平,算法时间简单
  • 缺点:排在长作业后的短作业需要等待很长时间,带权周转时间很大,对短作业来说用户体验不好
  • 饥饿问题:不会。

示例:

1761556115948

短作业优先(SJF)

短作业优先(Shortest Job First)

调度当前已经到达运行时间最短的作业运行。

  • 算法思想:追求最少的平均等待时间,最少的平均周转时间,最少的平均带权周转时间。

  • 算法规则:最短的作业/进程优先得到服务。

  • 调度:即可用于作业调度,也可用于进程调度。

    用于进程调度时称为”短进程优先”(SPF, Shortest Procss First)

  • 是否抢占:SJF和SPF是非抢占式算法。但是也有抢占式版本——最短剩余时间优先算法(SRTN, Shortest Remaining Time Next)

  • 优点:”最短的“平均等待时间,平均周转时间。

  • 缺点

    • 不公平。对短作业有利,对长作业不利。
    • 作业/进程的运行时间是由用户提供的,并不一定真实,不一定能做到真正的短作业优先。
  • 饥饿问题:会,甚至可能让长作业一直”饿死”

上面我们提到SJF调度算法的平均等待时间、平均周转时间最少。但这其实是不严谨的。

对于非抢占式的SJF调度算法,只有在所有进程同时到达时,即所有进程同时可运行时,SJF调度算法的平均等待时间,平均周转时间最少。

而对于抢占式的SFJ算法即最短剩余时间优先算法(SRTN),它才是真正的平均等待时间、平均周转时间最少。

示例:

  • 非抢占式:

1761556178984

  • 抢占式:

1761556214400

高响应比优先(HRRN)

高响应比优先(Highest Response Ratio Next)

  • 算法思想:要综合考虑作业/进程的等待时间和要求服务的时间。

  • 算法规则:在每次调度时先计算各个作业/进程的响应比,选择响应比最高的作业/进程为其服务。

    $$
    \text{响应比} = \frac{\text{等待时间} + \text{要求服务时间}}{\text{要求服务时间}}
    $$

  • 是否抢占:非抢占式算法。因此只有当前运行的作业/进程主动放弃处理机时,才需要调度,才需要计算响应比。

  • 优点

    • 综合考虑了等待时间和运行时间。
    • 等待时间相同时,要求服务时间短的优先。
    • 要求服务时间相同时,等待时间长的优先
    • 对于长作业来说,随着等待时间越来越长,其响应比会越来越大,从而避免了长期饥饿。
  • 饥饿问题:不会

示例:

1761556252379

总结

1761543465020

交互式系统调度算法

时间片轮转调度算法(RR)

时间片轮转(Round-Robin)

  • 如果时间片太大,使得每个进程都可以在一个时间片内就完成,则时间片轮转调度算法退化为先来先服务调度算法,并且会增大进程响应时间,因此时间片不能太大。
  • 如果时间片太小,进程切换过于频繁,系统花费大量的时间用来处理进程切换,从而导致实际执行任务的时间比例减少。因此时间片不能太小。
  • 算法思想:公平地、轮流地为各个进程服务,让每个进程在一定时间间隔内都可以得到响应。
  • 算法规则:按照各进程到达就绪队列的顺序,轮流的让各个进程执行一个时间片(如100ms)。若进程未在一个时间片内执行完,则剥夺处理机,将进程重新放到就绪队列队尾重新排队。
  • 调度:用于进程调度(只有作业放入内存建立了相应的进程后,才能被分配处理机时间片)。
  • 是否抢占:若进程未能在时间片内运行完成,将被强行剥夺处理机使用权,因此时间片轮转调度算法属于抢占式的算法。由时钟装置发出时钟中断来通知CPU时间片已到。
  • 优点:公平,响应快,适用于分时操作系统
  • 缺点
    • 由于高频率的进程切换,因此有一定开销
    • 不区分任务的紧急程序
  • 饥饿问题:不会。

示例:(时间片为2)

1761556296802

优先级调度算法

优先级调度算法(Priority scheduling)

根据优先级在创建后是否可以动态改变,可将优先级分为:

  • 静态优先级
  • 动态优先级
    • 调整优先级的时机:
      • 进程等待时间很久->适当提升优先级(响应比)
      • 进程运行时间很久->适当降低优先级
      • 进程频繁I/O操作->适当提升优先级

优先级排序:

  • 系统进程>用于进程
  • 前台进程>后台进程
  • 操作系统更偏好I/O繁忙型进程

    I/O设备可以和CPU并行的工作,让I/O繁忙型优先运行可以让I/O设备尽早的投入工作,可以提升资源利用率,系统吞吐量。

  • 算法思想:随着计算机的发展,特别是实时操作系统的出现,越来越多的应用场景需要根据任务的紧急程序来决定处理顺序。

  • 算法规则:每个作业/进程有各自的优先级,调度时选择优先级最高的作业/进程。

  • 调度

    • 作业调度:选择一个处于外存中后备队列的作业进入内存。
    • 进程调度:选择一个在内存中就绪队列的进程为他分配处理机。
    • 甚至还可以用于I/O调度
  • 是否抢占

    • 抢占:只需在进程主动放弃处理机时进行调度即可。
    • 非抢占:在就绪队列变化时,检查是否会发送抢占。
  • 优点

    • 用优先级区分紧急程度、重要程度,适用于实时操作系统。
    • 可灵活地调整对各种作业/进程的偏好程度。
  • 缺点:若源源不断地有高优先级进程到来,则可能导致饥饿。

  • 饥饿问题:存在

抢占式:1761546393178

非抢占式:1761546412044

多级反馈队列调度算法

多级反馈队列算法(Multilevel Feedback Queue)

  • 算法思想:对其他调度算法的折中权衡。
  • 算法规则
    1. 设置多级就绪队列,各级队列优先级从高到低,时间片从小到大
    2. 新进程到达时先进入第1级队列,按FCFS原则排队等待被分配时间片,若用完时间片进程还未结束,则进程进入下一级队列队尾。如果此时已经是在最下级的队列,则重新放回该队列队尾。
    3. 只有第k级队列为空时,才会为k+1级队头的进程分配时间片。
  • 调度:用于进程调度
  • 是否可抢占抢占式算法。在K级队列的进程运行过程中,若是更上级的队列中进入了一个新进程,则由于新进程处于优先级更高的队列中,因此新进程会抢占处理机,原来运行的进程放回k级队列的队尾。
  • 优点:
    • 对各类型进程相对公平(FCFS的优点)
    • 每个新到达的进程都可以很快等到响应(RR的优点)
    • 短进程只用较少的时间就可以完成(SPF的优点)
    • 不必实现估计进程的运行时间
    • 可灵活地跳转对各类进程的偏好程度(对于I/O阻塞的进程可以放回原队列保持优先级)
  • 缺点:可能导致饥饿问题。
  • 饥饿问题:会

示例:

1761558082456

总结

1761558384134

多级队列调度算法

系统中按进程类型设置多个队列,进程创建成功后插入某个队列。

例子:

1761558655204

队列间调度方式:

  • 固定优先级:高优先级空时低优先级进程才能被调度。
  • 时间片划分:队列分配不同的时间,如50%,40%,10%

各队列内部可以采取不同的调度策略

例子:

  • 系统进程队列采用优先级调度。
  • 交互式采用时间片轮转。
  • 批处理队列采用先来先服务。

多处理机调度

单处理机调度:只需决定让哪个就绪进程优先上处理机即可。

多处理机调度

  1. 用调度算法决定让哪个就绪进程优先上处理机。
  2. 还需要决定被调度的进程到底上哪个处理机

调度目标

  • 负载均衡:尽可能让每个CPU都同等忙碌。
  • 处理机亲和性:尽量让一个进程调度到同一个CPU上运行,以发挥CPU中缓存(Cache)的作用。

公共就绪队列

1761611071569

  • 所有CPU共享同一个公共就绪进程队列
  • 每个CPU空闲的时候,都会运行调度程序。,从公共就绪队列中选择一个进程运行。
  • 每个CPU访问公共就绪队列时需要上锁。

优点:可以天然的实现负载均衡。

缺点:各个进程频繁地换CPU运行。亲和性不好。

提升亲和性的方法:

  • 软亲和:由进程调度程序尽量保证”亲和性”
  • 硬亲和:由用户进程通过系统调用,主动要求操作系统分配固定的CPU,确保”亲和性”。

私有就绪队列

1761611522383

  • 每个CPU都有一个私有的就绪队列
  • CPU空闲时运行调度程序,从私有就绪队列中选择一个进程运行。

实现负载均衡:

  • Push迁移策略:
    • 一个特定的系统程序周期性检查每个处理器的负载,如果负载不平衡,就从忙碌CPU的就绪队列中一些就绪进程到空闲CPU的就绪队列。
  • PULL迁移策略:
    • 每个CPU运行调度策略时,周期性检查自身负载与其他cpu的负载。如果一个CPU负载很低,就从其他高负载CPU的就绪队列中一些就绪进程到自己的就绪队列。

实现亲和性:

  • 私有就绪队列天然的实现了处理机的亲和性。

第二章--处理机管理
http://blog.ulna520.com/2025/10/24/第二章--进程管理_20251024_143751/
Postigita
October 24, 2025
Lizenta