ps:大家可以先去看看上面文章里对操作系统的解释,对操作系统有一个大概的了解。
处理器管理
1. 进程
2. 进程调度
2.1.调度层次
-
高级调度(作业调度、长程调度)
在多道批处理操作系统环境下,从输入系统的一批作业中,按照预定的调度策略挑选若干作业进入内存,
为其分配资源并创建相应的用户进程。
作业:用户提交给操作系统计算的一个独立任务,生命周期(输入、后备、执行、完成)。
-
中级调度(平衡调度、中程调度)
根据内存资源情况决定内存中能容纳的进程数目,并完成进程内外存对换工作。
-
低级调度(进程/线程调度、短程调度)
根据某种规则决定就绪队列中哪个进程/线程获得处理器,并将处理器分配给它使用。
ps:低级调度是各类操作系统必备的功能。
作业与进程的关系
作业是任务实体,进程是完成任务的执行实体。没有作业,进程无事可做;没有进程,作业无法完成。
2.2.低级调度的基本类型
- 抢占式(剥夺式):高优先级进程可以剥夺低优先级进程;或者在运行时间片到的时候可以剥夺。
- 非抢占式(非剥夺式):一旦进程或线程占用CPU,则不再让出CPU直到进程运行结束或主动放弃CPU。
2.3.进程调度算法
-
先到先服务算法(非抢占式)------ FCFS
先请求CPU的进程被首先分配到CPU。
-
最短作业优先算法(非抢占式)------ SJF
以进入系统的作业所要求的CPU时间为标准,总选取估计计算时间最短的作业投入运行。
-
最短剩余时间优先算法(抢占式)------ SRJF
一个新作业进入就绪状态,如果新作业需要的CPU时间比当前正在执行的作业剩余下来还需的CPU时间短,
SRJF强行赶走当前正在执行的作业。
-
响应比最高者优先算法(非抢占式)------ HRRF
介于FCFS与SJF两者之间的折中算法,既考虑作业等待时间,又考虑作业的运行时间。
响应比 = 1 + 已等待时间/估计运行时间 -
优先级调度算法(抢占式/非抢占式)------ HPF
-
时间片轮转调度算法(抢占式)------ RR
调度程序每次把CPU分配给就绪队列首进程使用一个时间片,就绪队列中的每个进程轮流地运行一个时间片。
当这个时间片结束时,强迫一个进程让出处理器,让它排列到就绪队列的尾部,等待下一轮调度。
-
多级反馈列队调度(抢占式)------ MLFQ
(又称反馈循环队列或多队列策略)
系统多个就绪进程队列,较高优先级的队列一般分配给较短的时间片 。
处理器调度先从高级就绪进程队列中选取可占有处理器的进程,
只有在选不到时,才从较低级的就绪进程队列中选取。
ps:除了RR和MLFQ只能用于进程调度,其它调度算法在进程调度和作业调度均适用。
下面来应用一下:
ps:周转时间就是到达时间到结束时间 的时间间隔(在系统里的等待时间与运行时间之和)


3. 进程同步与互斥
3.1. 临界区与互斥
在并发编程中,临界区 (Critical Section)是指一个程序中仅允许 一个线程 或 进程 访问的代码片段。这些代码通常会访问 共享资源 ,比如内存、文件、数据库等。当多个线程或进程试图同时访问这些共享资源时,可能会导致数据不一致或其他并发问题。因此,需要一种机制来确保在任何时候,保证在 一个时刻只有一个线程或进程 能够访问 临界区 的代码。
这种机制就叫做 互斥:
互斥 (Mutual Exclusion)是计算机科学中一种用于 防止 多个进程或线程同时访问共享资源或 临界区 的机制。其主要目标是避免资源竞争和数据不一致的问题。互斥保证在任何时刻,最多只有 一个线程或进程 可以访问特定的共享资源,从而确保数据的完整性。
3.2. 互斥
实现 互斥 的方法主要包含如下几种:
| 方法 | 说明 |
|---|---|
| 软件互斥 | 依赖算法和程序设计来确保 临界资源 的独占 |
| 硬件互斥 | 使用CPU指令集中的 原子指令 来实现 临界资源 的独占 |
| 锁 | 操作系统提供的API,软件直接调用即可实现资源的独占 |
| 信号量 | 操作系统提供的API,可以使用 信号量 来实现锁的功能 |
3.3. 同步
同步是指多个 线程 为了协同完成某项任务,必须按照一定的顺序执行操作。它主要解决 线程 之间在执行过程中如何协调的问题,确保它们以预期的时序进行交互与合作。
互斥和同步的关系?
互斥是 同步 的一种特例,它用于保证多个 线程 在访问共享资源时不会发生冲突,即在同一时刻最多只有一个 线程 可以访问该资源。
同步的范畴更广,不仅包括 互斥 控制,还包括 线程 之间的顺序协调、条件等待、信号传递等机制。
简单来说:
- 互斥:解决"同一时刻只能有一个 线程 访问共享资源"的问题;
- 同步:解决" 线程 之间需要按照某种顺序协同执行"的问题。
信号量 (Semaphore)是一个 同步原语,相比 锁 ,信号量可以解决一些更加复杂的同步问题。
在逻辑上我们将 信号量 理解为一个整数计数值,用于表示可用资源的数量。
信号量提供两个 原子操作:
| 操作 | 作用 | 关键步骤 |
|---|---|---|
| P(wait) | 申请资源 | 1. 信号量-1; 2. 信号量>=0 → 继续; 3. 信号量<0 → 阻塞 |
| V(signal) | 释放资源 | 1. 信号量+1; 2.信号量>0 → 继续; 3. 信号量<=0 → 唤醒一个阻塞线程 |
3.4. 信号量应用
-
实现锁
当 信号量 的初始值为 1 时,可以把 信号量 当作 锁 使用:csemaphore mutex = 1; P1() { P(mutex); // critical section(临界区:独占资源) V(mutex); } P2() { P(mutex); // critical section V(mutex); } -
实现简单同步
下述的代码,可以保证执行完P1中的code1之后,才会执行P2中的code2:csemaphore s = 0; // 将信号量的初始值设置为 0 P1() { code1; // 先执行 code1 V(s); // 告诉线程 P2,code1 已经完成 ... } P2() { ... P(s); // 检查 code1 是否完成 code2; // 检查无误,运行 code2 }
3.5. 经典同步问题
下面是对一些同步问题的解析及相关代码:
经典同步问题
4. 死锁
4.1. 死锁的状态

上图中的进程就处于 死锁状态 。每个进程都既要又要,持有的不释放,想要的也得不到,也不允许其他进程去抢占自己所占有的,所有的进程和资源之间组成一个 循环链条。以上这些特点决定了系统进入了死锁状态。
4.2. 死锁产生的必要条件
只有以下四个条件同时满足,死锁 才会发生:
- 互斥条件(Mutual Exclusion): 指的是至少有一个资源必须处于非共享模式,也就是说,一次只有一个进程可以使用资源。如果其他进程请求该资源,那么请求的进程必须等到该资源的持有者释放该资源。
- 占有并等待(Hold and Wait): 指的是一个进程因请求资源而阻塞时,对当前获得的资源保持不放。换句话说,进程至少已经持有一个资源,但又申请新的资源;由于其他进程持有这些资源,所以它现在是阻塞的。
- 非抢占(No Preemption): 资源不能被抢占,也就是说,只有资源的持有者才可以释放它。资源在完全自愿的基础上被释放,不能被强行从持有进程中夺走。
- 循环等待(Circular Wait):存在一个进程资源的等待链,链中的每一个进程都在等待下一个进程所持有的资源。这导致了一个循环的等待链。
为了 避免死锁 ,需要 破坏 上述的任意一个条件。
4.3. 死锁避免
死锁避免 是系统级的算法,需要对系统的资源和实体进行抽象,进行统筹规划,其中最经典的算法是 银行家算法。
4.4. 死锁的检测和删除
为了能对系统是否已发生了 死锁 进行检测,必须:
- 用某种数据结构来保存资源的请求和分配信息:
- 提供一种算法,利用上述信息来检测系统是否已进入 死锁 状态。
一般来说,一种简单的建模方式是使用 资源分配图:
- 将系统中的所有资源和进程表示为图中的节点。
- 如果进程 P1 请求资源 R1,绘制从 P1 到 R1 的有向边。
- 如果资源 R1 分配给了进程 P2,绘制从 R1 到 P2 的有向边。
在构建完 资源分配图 ,可以通过使用 DFS 检查图中是否存在环路以判断是否存在 死锁。