计算机操作系统
参考资料
- 《Operating System Concepts(第 10 版)》
- https://blog.csdn.net/Royalic/article/details/119999404
learning outcomes
- 谈谈操作系统的 整体结构 与 核心功能
- 进程、线程、调度 的完整生命周期及其关键数据结构(PCB、VMA、inode)
- 内存管理(分区、分页、伙伴系统、页面置换)与 文件系统(inode、日志、挂载) 的工作原理
- 中断、I/O 调度、设备驱动 的基本流程
- 设计 线程池 并正确使用同步原语保证线程安全
- 说说 死锁、饥饿、实时调度
看完下面的内容再回来尝试一下
操作系统概述
定义
操作系统(Operating System, OS) 是一种 系统软件,位于硬件与用户或应用程序之间
负责 控制、管理 计算机的软硬件资源,并为上层程序提供 统一、抽象且安全的接口
基本功能
-
进程/线程管理
负责创建、调度、终止进程/线程,提供同步与通信机制 -
内存管理
分配/回收内存、实现虚拟内存、页面置换 -
文件系统
抽象存储设备为文件/目录,提供持久化存取 -
设备管理
统一管理 I/O 设备,提供驱动程序、缓冲、调度
现代 OS 还会提供 网络栈、系统安全、资源隔离(容器/虚拟化) 等扩展功能
特征
| 特征 | 含义 |
|---|---|
| 并发性(Concurrency) | 多个程序/线程在同一时间段交错执行(时间片轮转等),例如进程/线程调度 |
| 并行性(Parallelism) | 真正的 同时 执行,依赖多核/多处理器硬件 |
| 共享性 | 资源(CPU、内存、I/O)可被多个执行体同时使用,例如共享内存、文件系统 |
| 虚拟化(Virtualization) | 把 物理实体 抽象为 若干逻辑实体(如虚拟内存、虚拟设备),例如页表、虚拟机 |
| 异步性(Asynchrony) | 事件驱动的处理方式,调用者不必阻塞等待 |
| 可移植性 | OS 通过硬件抽象层(HAL)实现跨平台,例如 POSIX |
“并发”不等同于“并行”。并发是 调度层面的交错,并行是 硬件层面的同时间执行
虚拟化和异步的前提是 并发:只有在并发环境下,才能把资源抽象为逻辑实体或采用非阻塞 I/O
时分复用:不同程序 分时使用 硬件资源,提高资源利用率
空分复用:将物理磁盘虚拟为逻辑磁盘,例如电脑的 C、D 盘等
按使用场景分类
| 类别 | 典型系统 | 主要特征 |
|---|---|---|
| 批处理系统 | IBM OS/360 | 无交互、作业调度为主 |
| 分时系统 | Unix、VMS | 多用户共享 CPU,采用时间片轮转 |
| 实时系统 | VxWorks、RTLinux | 确保硬实时或软实时响应 |
| 嵌入式系统 | FreeRTOS、Zephyr | 资源受限、定制化驱动 |
| 通用操作系统 | Windows、Linux、macOS | 支持图形 UI、网络、丰富的服务 |
系统结构
内核结构模型
| 模型 | 说明 | 优缺点 |
|---|---|---|
| 单体内核(Monolithic) | 所有核心服务(进程管理、文件系统、网络栈等)在同一地址空间 | 高效、实现简单;缺点是模块间耦合度高,出错风险大 |
| 微内核(Microkernel) | 只保留最小的进程调度、IPC、基本内存管理,其余服务运行在用户态 | 高可靠性、易扩展;但 IPC 开销相对大 |
| 混合内核(Hybrid) | 兼具单体内核的效率和微内核的模块化(如 Windows NT、现代 Linux) | 实际使用最广 |
| 外核/Exokernel | 将硬件抽象最小化,直接把硬件资源暴露给上层库 | 极端灵活,适合研究实验 |
Linux 采用 混合内核:核心功能在内核空间,驱动、文件系统等可编译为模块(loadable kernel modules, LKM)
用户态 vs. 内核态
| 特性 | 用户态 | 内核态 |
|---|---|---|
| 访问权限 | 受限,只能访问用户空间 | 完全访问硬件、内存 |
| 执行指令 | 只能执行非特权指令 | 可执行特权指令(I/O、控制寄存器) |
| 切换方式 | 系统调用、异常、软中断 | 硬件中断、系统调用返回 |
| 开销 | 低 | 需要保存/恢复上下文,开销相对大 |
系统调用 是用户态程序进入内核态的唯一受控入口,如 read()、write()、fork() 等。
进程 vs. 线程
| 项目 | 进程 | 线程 |
|---|---|---|
| 资源拥有 | 拥有独立的地址空间、打开的文件描述符、PCB | 与同属进程的线程共享地址空间、文件描述符、信号 |
| 切换开销 | 较大(需要切换页表、TLB) | 较小(仅切换寄存器、栈) |
| 创建/销毁 | 较慢(fork()) |
较快(pthread_create()) |
| 适用场景 | 需要强隔离、不同安全域 | 需要高并发、共享数据的场景 |
进程管理
进程的概念与控制块 PCB
进程 是 资源分配和调度的基本单位,是 程序 在 运行时 的 动态实例
Process Control Block 是进程存在的唯一标识,记录进程的状态和运行的信息
典型的 PCB(结构体示例):
|
|
PCB 中记录的关键字段:
- PID:唯一标识
- 状态:
TASK_RUNNING、TASK_INTERRUPTIBLE、TASK_UNINTERRUPTIBLE、TASK_STOPPED、TASK_ZOMBIE等 - 上下文:保存寄存器、程序计数器、栈指针,以便 上下文切换 时恢复
- 地址空间:指向页表/段表结构
- 打开的文件:文件描述符表
- 调度信息:优先级、时间片、调度策略
进程状态模型(五状态 + 挂起)
|
|
- 创建(new):系统为进程分配 PCB,但尚未分配全部资源。
- 就绪(ready):所有资源(内存、文件句柄)已就绪,等待 CPU。
- 运行(running):获得 CPU,正在执行指令。
- 阻塞(blocked):因等待 I/O、信号、同步对象等而主动放弃 CPU。
- 挂起(suspended):进程已被换出至磁盘(Swap)或被管理员暂停。
- 终止(exit):进程结束,资源回收,PCB 进入 僵尸(zombie) 状态直至父进程
wait()。
进程的创建、执行与终止
| 系统调用 | 作用 | 关键点 |
|---|---|---|
fork() |
创建子进程,复制父进程的地址空间(写时复制) | 返回值:子进程 0、父进程子 PID |
execve() |
用新程序替换当前进程映像 | 只保留 PID、打开的文件描述符(可设 FD_CLOEXEC) |
vfork() |
为 exec 设计的轻量 fork,父进程在子进程 exec 前阻塞 |
用于性能敏感的场景 |
clone() |
Linux 特有,可控制子进程共享哪些资源(如线程) | clone() + CLONE_VM 实现线程 |
exit() |
结束进程,返回退出码 | 触发资源回收、父进程 wait |
wait()/waitpid() |
父进程收集子进程退出状态 | 防止僵尸进程 |
上下文切换(Context Switch)
- 保存当前进程上下文(寄存器、程序计数器、栈指针)到 PCB。
- 切换页表(若进程地址空间不同)。
- 调度器选择下一个就绪进程。
- 恢复新进程上下文,返回到用户态或内核态继续执行。
开销:约 1–5 µs(取决于硬件、TLB 刷新、缓存失效)。
优化:使用 TLB 刷新延迟、CPU 亲和性(CPU affinity)等技术。
进程调度层次
| 调度层次 | 名称 | 作用 |
|---|---|---|
| 长程调度(作业调度) | job scheduler |
决定哪些作业进入系统(系统负载控制),对应 作业管理 |
| 中程调度(交换调度) | swapper |
将进程从主存换出至 Swap,或换回;实现 多道程序 |
| 短程调度(CPU 调度) | CPU scheduler |
从就绪队列挑选进程分配 CPU(时间片轮转、优先级等) |
进程同步
四大原则
| 原则 | 含义 |
|---|---|
| 互斥(Mutual Exclusion) | 同一时刻只能有 一个 进程进入临界区 |
| 进度(Progress) | 当没有进程在临界区时,不阻塞 进入临界区的进程 |
| 有界等待(Bounded Waiting) | 对每个进程,进入临界区的等待次数 有上限(防止饥饿) |
| 顺序性(Ordering) | 对共享资源的所有操作必须 按程序顺序 执行(防止重排) |
这四条原则是 正确实现同步 的理论基石。若任意一条被破坏,都可能导致 死锁、饥饿或竞争错误。
常用原语
| 原语 | 类型 | 关键特性 |
|---|---|---|
| 互斥锁(Mutex) | 阻塞 | lock()/unlock(),保证互斥 |
| 自旋锁(Spinlock) | 非阻塞(自旋) | 适用于短临界区,避免上下文切换 |
| 读写锁(RWLock) | 阻塞 | 多读者共享,写者独占 |
| 信号量(Semaphore) | 阻塞/计数 | wait()/post(),可实现资源计数 |
| 条件变量(Condition Variable) | 阻塞 | wait() + signal()/broadcast(),配合互斥锁 |
| 屏障(Barrier) | 阻塞 | 多线程同步点,全部到达后放行 |
| 原子操作(Atomic) | 非阻塞 | compare_and_swap、fetch_add 等硬件指令 |
| 内存屏障(Memory Barrier) | 非阻塞 | 防止指令/内存访问重排 |
实现示例(POSIX):
|
|
死锁(Deadlock)
| 类型 | 描述 |
|---|---|
| 死锁 | 进程之间由于 竞争资源 或者 彼此通信 或者 调度顺序不当 所造成的阻塞现象 |
| 饥饿 | 进程长期得不到资源 |
| 死循环 | 代码存在 BUG |
- 死锁产生的前提(死锁的必要条件)
| 条件 | 说明 |
|---|---|
| 互斥(Mutual Exclusion) | 资源一次只能被一个进程占用 |
| 占有且等待(Hold and Wait) | 进程已占有至少一个资源,同时请求新的资源 |
| 不可剥夺(No Preemption) | 已分配的资源只能由占有进程自行释放,不能被强制抢占 |
| 循环等待(Circular Wait) | 存在进程 → 资源 → 进程的环形等待链,链中的每个进程都在等待下一个进程所占有的资源 |
只要破坏其中任意一条,就能 预防 死锁。
死锁处理策略
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 预防(Prevention) | 通过破坏必要条件(如禁止占有且等待)来根除死锁 | 系统对响应时间要求不高 |
| 避免(Avoidance) | 动态检查资源分配是否会导致不安全状态(如 银行家算法) | 资源种类有限且需求可预测 |
| 检测(Detection) | 运行时检测死锁(资源分配图、等待图)并触发恢复 | 资源需求不可预知,且系统能容忍短暂死锁 |
| 恢复(Recovery) | 终止或回滚进程,抢占资源 | 检测到死锁后执行 |
-
银行家算法(Deadlock Avoidance)
- 系统状态:
Available: 各类资源当前可用数量Max: 每个进程最大需求矩阵Allocation: 已分配矩阵Need = Max - Allocation
- 安全性检查:模拟分配后是否仍能满足所有进程的
Need。若能,则系统处于 安全状态,否则拒绝分配。 - 实现要点:
- 只在 可抢占 环境下有效(如内存页可回收)
- 需要 进程提前声明最大需求,不适用于动态需求变化的场景。
- 系统状态:
-
死锁检测(资源分配图)
- 资源分配图(RAG):节点分为 进程(圆)和 资源(方),边表示 请求 或 分配。
- 等待图(Wait‑For Graph, WFG):仅保留进程节点,若
Pi → Pj表示Pi正在等待Pj持有的资源。环路即死锁。
-
恢复策略
方法 说明 终止进程 直接杀死一个或多个进程,释放资源(优先终止低优先级或占用资源最多的进程) 资源抢占 强制回收进程持有的可抢占资源(需要进程能安全回滚) 回滚 将进程回滚到安全检查点(事务式系统)
进程调度
计算机通过决策决定哪个进程获得 CPU 使用权
-
长程调度
- 目标:控制系统负载、实现 多道程序(提高 CPU 利用率)。
- 策略:
- FCFS(先来先服务):简单但可能导致 短作业延迟。
- 多级队列:将作业按优先级、资源需求划分不同队列。
- 作业控制块(JCB):记录作业的状态、所需资源、优先级等。
-
短程调度(CPU 调度)
进程主动放弃(非抢占),正常结束、调用
exit()、sleep()、wait()、I/O 阻塞系统强制抢占,时间片耗尽、出现更高优先级进程、I/O 中断、系统调用sched_yield()
调度机制与常见算法
| 机制 | 说明 |
|---|---|
| 排队(Queue) | 就绪进程排成链表/队列,依据调度算法挑选 |
| 委派(Dispatch) | 调度器将 CPU 分配 给选中的进程(上下文切换) |
| 上下文切换(Context Switch) | 保存/恢复 PCB,切换页表、TLB 等 |
| 类别 | 算法 | 关键特性 | 适用场景 |
|---|---|---|---|
| 非抢占 | FCFS(First‑Come‑First‑Served) | 按到达顺序,平均等待时间大 | 批处理系统 |
| 非抢占 | SJF(Shortest Job First) (非抢占) |
最短作业优先,最小化平均等待时间,但易产生饥饿 | 作业长度已知的批处理 |
| 抢占 | RR(Round‑Robin) | 时间片轮转,公平性好 | 分时系统、交互式 |
| 抢占 | Priority Scheduling(抢占式) | 按优先级调度,优先级相同时可采用 RR | 实时系统、资源紧张 |
| 抢占 | Multilevel Queue | 多个队列,每队列采用不同算法,队列间有固定优先级 | 多类作业(交互式 vs. 批处理) |
| 抢占 | Multilevel Feedback Queue (MLFQ) | 进程可在队列间迁移,动态调节响应时间 | 兼顾交互性与吞吐量 |
| 实时 | Rate‑Monotonic (RM) | 固定优先级,周期越短优先级越高(硬实时) | 硬实时系统 |
| 实时 | Earliest Deadline First (EDF) | 动态优先级,最早截止时间的任务优先(软/硬实时) | 动态实时调度 |
| 混合 | CFS (Completely Fair Scheduler) – Linux | 基于红黑树的 虚拟运行时间,近似公平 | 通用 Linux 系统 |
调度评价指标
| 指标 | 含义 |
|---|---|
| CPU 利用率 | CPU 实际工作时间占总时间的比例 |
| 吞吐量(Throughput) | 单位时间内完成的作业/进程数 |
| 周转时间(Turnaround Time) | 作业提交到完成的总时间 |
| 等待时间(Waiting Time) | 作业在就绪队列中等待的时间 |
| 响应时间(Response Time) | 第一次调度到进程开始执行的时间(交互式系统关键) |
| 公平性(Fairness) | 资源分配是否对所有进程均等(避免饥饿) |
存储管理
内存的分配与回收
-
动态分区分配算法
算法 原理 优点 缺点 首次适应(First‑Fit) 从低地址向高地址扫描,找到第一个足够大的空闲块 实现简单,搜索时间短 易产生 外部碎片 最佳适应(Best‑Fit) 在所有空闲块中挑选最小的满足需求的块 减少碎片 需要遍历全部空闲块,搜索时间长 最差适应(Worst‑Fit) 选取最大的空闲块 产生的大块碎片易合并 仍会产生碎片,且浪费大块空间 快速适应(Next‑Fit) 类似首次适应,但从上一次分配结束位置继续搜索 对循环负载有优势 与首次适应类似的碎片问题 -
内存回收的过程
当回收区出现在空闲区的不同位置的时候,回收区和空闲区是直接合并,还是需要创建新的空闲节点?
新的空闲区使用的地址是哪一个?- 立即合并(Immediate Coalescing):释放块后立即检查前后相邻块是否空闲,若是则合并为更大的块。
- 延迟合并(Deferred Coalescing):将空闲块挂入空闲链表,等到 分配请求 或 内存回收周期 再统一合并。
- 合并策略:
- 地址顺序链表:空闲块按起始地址排序,便于检查相邻块。
- 双向链表:便于向前/向后遍历合并。
新空闲块的起始地址 为 被释放块的起始地址;若合并后形成更大的块,则该块的起始地址为最左侧块的地址。
虚拟内存与分页
虚拟内存概念
- 虚拟地址空间:每个进程拥有独立的 32/64 位线性地址空间。
- 页面(Page):固定大小的块(常见 4 KB、2 MB、1 GB 大页),是虚拟内存管理的基本单元。
- 页表(Page Table):记录 虚拟页号 ↔ 物理帧号 的映射关系。
- TLB(Translation Lookaside Buffer):CPU 中的高速缓存,用于存放最近使用的页表项,降低地址转换延迟。
页面置换算法
| 算法 | 思路 | 优点 | 缺点 |
|---|---|---|---|
| FIFO | 先进入的页先淘汰 | 实现简单 | Belady 异常(可能更差) |
| LRU | 最近最少使用的页淘汰 | 接近最优 | 需要维护访问时间,开销大 |
| Clock(Second‑Chance) | 环形指针 + 访问位 | 近似 LRU,硬件实现友好 | 仍有一定误差 |
| NRU(Not Recently Used) | 定期清除访问位,分四类 | 简单、适用于 OS 定时器 | 可能产生误淘汰 |
| 随机(Random) | 随机淘汰 | 实现最简 | 性能不可预测 |
| 工作集(Working Set) | 维持进程最近 N 条指令的页面集合 | 减少缺页率、避免抖动 | 需要额外统计开销 |
交换(Swapping)与页面置换的关系
- Swap 区:磁盘上专门用于保存被换出的页面或整个进程的 交换空间。
- 页面置换:当物理内存不足时,页面 被写入 Swap;当页面再次被访问时,触发 缺页异常,内核将其调回内存(可能再置换其他页面)。
Linux 中的 Swap 采用 页面级 交换(默认 4 KB),并通过 swapiness 参数控制换出倾向。
伙伴系统(Buddy System)
- 原理:将空闲内存块划分为 2 的幂次大小的 伙伴(如 2 KB、4 KB、8 KB…),当分配请求到来时,找最小的足够块;若块太大则 拆分 成两个相同大小的伙伴;释放时若其伙伴也是空闲,则 合并 成更大的块。
- 优点:快速分配/合并,碎片率低,适合 页框分配(Linux 物理页帧)和 内核对象(Slab)管理。
- 缺点:只能分配 2 的幂次大小,导致 内部碎片。
Linux 的存储管理
常用命令:
free -h、cat /proc/meminfo、vmstat、top、htop、cat /proc/[pid]/smaps。
Buddy 内存管理算法:解决内存外碎片的问题
Swap 空间是 Linux 系统的交换空间
是磁盘的一个分区,在初始化系统时配置的
当内存满时,系统会将一些内存交换至 Swap 空间
| Swap 空间 | 虚拟内存 |
|---|---|
| 操作系统概念 | 进程概念 |
| 解决 系统的 物理内存不足问题 | 解决 进程的 物理内存不足问题 |
文件管理
文件的抽象层次
- 用户视图:文件名、路径、权限、属性(size、mtime、atime)。
- VFS(Virtual File System)层:统一的文件系统抽象(
struct file,struct inode),实现跨文件系统的统一接口。 - 具体文件系统实现:如 ext4、xfs、btrfs、vfat、ntfs,负责磁盘块的布局、目录结构、日志(journal)等。
关键概念
| 概念 | 说明 |
|---|---|
| inode | 文件元数据结构,存放文件大小、权限、时间戳、指向数据块的指针(直接、间接、双间接、三间接) |
| 目录 | 特殊文件,内容是 文件名 ↔ inode 编号 的映射 |
| 超级块(Superblock) | 文件系统的全局信息(块大小、inode 数量、空闲块位图) |
| 文件描述符(fd) | 进程打开文件后得到的整数句柄,映射到 文件表项 |
| 文件系统挂载(mount) | 将文件系统的根目录挂到全局目录树的某个挂载点(如 /mnt/data) |
| 日志(Journal) | 记录元数据修改的事务日志,防止系统崩溃导致文件系统不一致(ext3/4、xfs) |
常见文件系统对比
| 文件系统 | 最大文件大小 | 最大容量 | 特点 |
|---|---|---|---|
| FAT32 | 4 GB | 2 TB | 兼容性好,适用于 U 盘、移动设备 |
| NTFS | 16 EB | 256 TB | Windows 主流,支持 ACL、压缩、加密 |
| ext2 | 2 TB | 32 TB | 传统 Linux,非日志 |
| ext3 | 2 TB | 32 TB | 在 ext2 基础上加入日志 |
| ext4 | 16 TB | 1 EB | 延迟分配、extent、校验和、日志 |
| XFS | 8 EB | 8 EB | 高并发、大文件、延迟分配 |
| Btrfs | 16 EB | 16 EB | 子卷、快照、RAID、写时复制(COW) |
文件操作系统调用(POSIX)
| 系统调用 | 功能 | 常见参数 |
|---|---|---|
open() |
打开文件或创建新文件 | pathname, flags, mode |
read() |
从文件读取数据 | fd, buf, count |
write() |
向文件写入数据 | fd, buf, count |
lseek() |
移动文件偏移指针 | fd, offset, whence |
close() |
关闭文件描述符 | fd |
stat() / fstat() |
获取文件属性 | pathname / fd, struct stat *buf |
unlink() |
删除文件 | pathname |
mkdir() |
创建目录 | pathname, mode |
chmod() |
改变权限 | pathname, mode |
mmap() |
将文件映射到进程地址空间 | addr, length, prot, flags, fd, offset |
文件描述符表:每个进程维护一个 打开文件表(指向全局 系统文件表),实现 共享打开文件(如
fork后子进程共享同一fd)。
设备管理与 I/O
设备分类
| 类别 | 示例 | 访问方式 |
|---|---|---|
| 字符设备 | 键盘、串口、终端、打印机 | 按字符流顺序读写(/dev/tty*) |
| 块设备 | 硬盘、SSD、U 盘、光盘 | 按块(sector)随机读写(/dev/sda) |
| 网络设备 | 网卡、虚拟网卡 | 通过套接字(socket)层抽象 |
| 特殊设备 | /dev/null、/dev/zero、/dev/random |
虚拟文件系统(tmpfs)提供特殊行为 |
设备驱动模型(Linux)
- 字符设备驱动:实现
file_operations(open, read, write, ioctl, poll)。 - 块设备驱动:实现
block_device_operations(submit_bio, getgeo),配合 I/O 调度器。 - 网络设备驱动:实现
net_device_ops(ndo_start_xmit, ndo_open, ndo_stop)。
驱动注册后会在 /dev 生成对应的 设备文件,用户通过系统调用访问。
中断处理(Interrupt Handling)
-
为什么需要中断?
- 异步事件:外设(键盘、网卡)在任意时刻需要 CPU 关注。
- 提高 CPU 利用率:CPU 不必轮询 I/O,能够在 I/O 完成时立即响应。
- 实现实时响应:对高优先级硬件事件(如时钟)进行及时处理。
-
中断的分类
类型 示例 触发方式 内部中断(Exception / Fault) 除零、页面错误、非法指令 CPU 在执行指令时检测 外部硬件中断 键盘、网卡、定时器 设备向 IRQ 线发送信号 软件中断(System Call) int 0x80、syscall程序显式触发,进入内核态 可屏蔽中断(Maskable) 大多数外设中断 可被 cli/sti或 CPU 中断屏蔽位屏蔽不可屏蔽中断(NMI) 硬件错误、看门狗 不能被屏蔽,最高优先级 -
中断处理流程(以 Linux 为例)
- 中断请求(IRQ):外设向中断控制器(APIC / PIC)发送信号。
- CPU 响应:CPU 通过 中断向量(Interrupt Vector Table)定位对应的 中断服务例程(ISR)。
- 保存上下文:CPU 自动压栈保存 寄存器、EFLAGS、CS/EIP(或 RIP)等。
- 进入中断处理程序:
- Top‑half(硬件中断上下文)完成快速处理(如读取状态寄存器、确认中断、唤醒等待队列)。
- Bottom‑half(软中断、tasklet、工作队列)在稍后以 进程上下文 完成耗时操作(如磁盘 I/O、网络协议栈处理)。
- 恢复上下文:执行 IRET(x86)或 eret(ARM),恢复原先进程的寄存器并返回。
中断屏蔽:在 ISR 中常使用
local_irq_save/restore防止同一中断嵌套。
中断共享:同一 IRQ 线可挂载多个设备,驱动在 ISR 中通过 设备链表 判断是哪一个设备触发。 -
常见中断相关系统调用 / 接口
接口 说明 request_irq()注册 ISR(Linux) free_irq()释放 IRQ enable_irq()/disable_irq()局部屏蔽/解除屏蔽 irq_set_affinity()绑定中断到特定 CPU(NUMA) ioctl()通过系统调用向驱动发送控制命令(如 FIONREAD)
I/O 调度(Disk Scheduling)
| 算法 | 思路 | 适用场景 |
|---|---|---|
| FCFS | 按请求到达顺序服务 | 负载轻、实现简单 |
| SSTF(Shortest Seek Time First) | 选择最近磁头位置的请求 | 减少寻道时间,但可能产生 饥饿 |
| SCAN(Elevator) | 磁头在一个方向上服务请求,到达边界后反向 | 兼顾公平与效率 |
| C‑SCAN(Circular SCAN) | 类似 SCAN,但磁头到达边界后回到起点,形成循环 | 防止方向性饥饿 |
| LOOK / C‑LOOK | 与 SCAN/C‑SCAN 类似,但磁头只到达最后一个请求的最远位置再反向 | 更高效 |
| Deadline / CFQ(Linux) | 为 I/O 请求设定截止时间或按进程权重分配时间片 | 多任务、实时需求 |
线程与线程池
线程概念
- 线程(Thread) 是 进程内部的执行流,共享进程的 地址空间、文件描述符、信号处理 等资源。
- 轻量级进程(LWP):在某些系统(如 Solaris)中,线程被实现为 LWP,内核直接调度。
- 用户态线程(如 Green Threads)在用户空间调度,不需要内核介入,适用于 I/O 密集型协程框架。
线程的创建与管理(POSIX 示例)
|
|
pthread_create→ 内核clone()系统调用(创建新线程)。pthread_join→ 等待线程结束并回收资源。
线程池设计模式
为什么使用线程池?
- 降低创建/销毁开销:线程的栈、调度信息、内核对象的分配成本较高。
- 控制并发度:通过固定线程数限制系统资源占用,防止 线程风暴。
- 任务调度解耦:生产者只负责提交任务,消费者(工作线程)负责执行。
典型结构(伪代码)
|
|
关键组件
| 组件 | 作用 | 常用同步原语 |
|---|---|---|
| Task | 包含待执行的函数指针、参数、返回值、状态标记 | - |
| WorkThread | 循环从任务队列取任务并执行;支持 平滑退出 | pthread_mutex, pthread_cond |
| ThreadPool | 负责创建/销毁工作线程、维护任务队列、提供 submit() 接口 |
mutex + condition variable |
| Future / Promise | 任务提交后返回的 句柄,可在以后查询结果或阻塞等待 | std::future(C++)、concurrent.futures(Python) |
线程安全实现(POSIX 示例)
|
|
- 生产者 调用
enqueue(),消费者(工作线程)循环调用dequeue()。 - 当
stop为真时,所有线程安全退出,防止 死锁。
常见实现(语言/库)
| 语言 | 库 / 框架 |
|---|---|
| C++ | std::thread + std::async / Boost.Asio |
| Java | java.util.concurrent.ThreadPoolExecutor |
| Python | concurrent.futures.ThreadPoolExecutor、multiprocessing.pool.ThreadPool |
| Go | Goroutine + worker pool(channel + select) |
| Rust | rayon、tokio(异步) |
问题自测
- 进程状态转换图、四大同步原则、死锁必要条件?
- 银行家算法 检查安全状态?
- 解释 TLB Miss、Cache Miss、Page Fault 的区别与处理流程。
- 比较 FCFS、SJF、RR、MLFQ 的优缺点并给出适用场景。