第 11 讲:操作系统、抽象与系统调用
不要把操作系统背成“进程管理、内存管理、设备管理、文件系统”四个名词。更有用的理解是:OS 站在应用程序与硬件之间,一边隐藏硬件细节,一边仲裁多个程序对有限资源的竞争。
从 hello 程序看见 OS
一个看似只有 printf 的程序,从输入命令到屏幕上出现字符,大致要经过:
- Shell 解析命令,通过
fork建立子进程; exec请求内核检查可执行文件,读取 ELF 头与程序头;- 内核为代码、数据、堆和栈建立虚拟地址映射,设置入口地址和 CPU 上下文;
- 调度器让该进程获得 CPU;
- 首次访问尚未在内存中的页时,发生缺页,内核从文件或交换区调页;
printf最终进入write系统调用,内核检查用户缓冲区,再把字节交给伪终端和设备驱动;- 窗口系统将字符转成像素,显示设备才真正改变。
这条链路几乎串起了整门课:进程、调度、虚拟内存、文件、I/O、中断和保护。
两种视角:抽象与资源管理
自顶向下:把复杂硬件变简单
如果没有 OS,读一段文件可能要直接操作控制器寄存器,处理旋转延迟、中断和错误码。OS 用抽象替换这些细节:
| 复杂的物理对象 | OS 提供的抽象 |
|---|---|
| CPU 的分时使用 | 进程、线程 |
| DRAM 与地址转换 | 每个进程独立的地址空间 |
| 磁盘扇区和块 | 文件、目录 |
| 控制器和设备寄存器 | 统一的 open/read/write/ioctl 接口 |
抽象不是“美化命名”,而是把不稳定的物理细节隔离在稳定接口之下。
UI、API、ABI、ISA 分别隔开哪两层
课件把计算机系统中的接口分成四个常见层次:
| 接口 | 面向谁 | 约定的内容 |
|---|---|---|
| UI | 人与应用/系统 | 命令、窗口、交互方式 |
| API | 源代码与库/OS 服务 | 函数名、参数和语义,如 POSIX read |
| ABI | 已编译程序与运行环境 | 调用约定、寄存器、对象格式、系统调用号 |
| ISA | 软件与处理器 | 指令、寄存器、异常和内存模型 |
API 相同不保证二进制可直接运行,因为 ABI 可能不同;ABI 最终又建立在 ISA 和 OS 的进程模型上。分层的价值是让一层内部替换时,尽量不迫使所有上层一起重写。
自底向上:在竞争者之间分配资源
同一时刻有多个程序想用 CPU、内存、磁盘和打印机。OS 需要回答:
- 给谁:调度和分配策略;
- 给多少:时间片、页框数、缓冲区大小;
- 何时收回:进程退出、页面置换、设备释放;
- 如何隔离:用户态/内核态、页权限、文件权限。
这是 OS 的另一面:它不仅让硬件“好用”,还要让共享“可控”。
为什么会有批处理、多道和分时
操作系统的发展是硬件矛盾推动的:
- 批处理:人的操作太慢,把作业成批交给监控程序自动衔接;
- 多道程序:一个程序等 I/O 时 CPU 空闲,于是在内存里同时放多个程序,交替使用 CPU;
- 分时:用户需要交互性,于是把 CPU 时间分成小片,让多个终端用户都感觉在独占计算机。
多道带来并发,也带来了隔离、同步、调度和死锁问题。
从“没有 OS”到现代系统的因果线
课件用较长的历史线说明:操作系统不是一次设计出来的,而是每一代硬件和使用方式暴露新矛盾后逐层长出来的。
- 早期电子管计算机没有 OS,程序员直接预约机器、装入程序和操纵设备;CPU 的昂贵时间大量耗在人工作业衔接上。
- 监控程序和联机/脱机批处理把作业自动串起来;脱机输入又让较慢的卡片、磁带准备工作不占主机。
- 晶体管和中断等硬件条件成熟后,多道程序让 CPU 在某道作业等 I/O 时切去运行另一道。
- 分时系统用短时间片和终端支持交互。MULTICS、UNIX、IBM VM/360 等系统分别探索了分时、可移植系统和虚拟机。
- PC 普及后,CP/M、DOS、Windows 把 OS 带到个人桌面;UNIX 经 C 语言重写形成可移植系统传统,GNU/Linux 延续了这一接口和工具链。
- 网络、工作站集群、云、分布式与嵌入式/实时场景,又把资源管理边界扩到多机或具有硬截止期的设备。
这条历史线真正要记的是“矛盾 → 机制”:人机速度差催生批处理,CPU/I/O 速度差催生多道,交互需求催生分时,多种硬件和工作负载又催生可移植接口、虚拟化和实时调度。
网络 OS、分布式 OS 与实时系统
- 网络操作系统让多台各自独立的机器通过显式远程登录、文件或网络服务协作,用户仍知道资源在哪台机器;
- 分布式操作系统试图把多机资源包装成更统一的系统映像,位置、迁移和故障处理更多由系统隐藏;
- 实时系统首先要求在规定时间内可预测地响应。硬实时错过截止期就是系统失败,软实时允许偶发超时但质量下降。
“快”不等于“实时”:平均运行很快但尾延迟不可控,仍不能给硬实时保证。
硬件为什么决定 OS 的做法
课件回顾处理器流水线、内存、Cache、磁盘、控制器和总线,是为了建立一个事实:计算、访存和 I/O 的速度严重失配。
- 流水线和多核使 CPU 可以快速推进多条执行流,也让并发和内存可见性更复杂;
- 寄存器、Cache、DRAM、磁盘/SSD 形成容量越大通常越慢的层次,OS 用缓存和虚拟内存跨层搬数据;
- I/O 设备由控制器寄存器暴露状态,挂在总线上;中断让设备主动通知 CPU,DMA 让控制器直接在设备与内存间搬块;
- 磁盘按柱面、磁道和扇区组织,机械寻道/旋转使请求顺序显著影响性能。
因此,缓存、异步 I/O、并发执行和调度不是互不相关的技巧,都是在隐藏长延迟并让快部件不要干等慢部件。
并发、共享、虚拟和异步
课件将现代 OS 的基本特征归纳为:
- 并发:多个活动在时间上重叠推进,不等于多核上真正同时的并行;
- 共享:多个进程共同使用有限资源;
- 虚拟:用时分复用或空分复用,把一份物理资源包装成多份逻辑资源;
- 异步:进程以“执行—暂停—再执行”的不可预知速度推进。
后三者都与并发有关:如果只有一个程序独占机器,许多难题根本不存在。
OS 要管理哪些工作
课件将功能展开为五类,后续各讲正好逐一回答:
- 处理机管理:建立/撤销进程线程,保存状态,调度与同步;
- 存储器管理:分配回收、地址转换、保护、共享和虚拟内存;
- 设备管理:设备分配、驱动、缓冲、中断和错误处理;
- 文件管理:命名、目录、块分配、共享、保护和持久一致性;
- 作业与用户接口:接收作业/命令,组织执行流程并报告结果。
方便性、资源利用率、吞吐、响应、安全与可扩展性经常冲突,所以 OS 设计的常态是权衡,不是把某一个指标单独做到最大。
用户态、内核态与保护
如果普通应用能直接修改页表、关中断或操作磁盘控制器,一个错误就可以摧毁整台机器。处理器因此提供至少两种权限级:
- 用户态:只能执行非特权指令,受地址空间和访问权限限制;
- 内核态:可执行特权指令,管理页表、中断、设备等全局资源。
从用户态进内核,必须经过受控入口:
| 类型 | 触发来源 | 典型例子 |
|---|---|---|
| 中断 | CPU 外部,异步 | 时钟到期、网卡收到数据 |
| 陷入/系统调用 | 程序主动请求 | read、fork、mmap |
| 故障/异常 | 当前指令无法正常完成 | 缺页、除零、访问越界 |
一次系统调用发生了什么
- 用户程序把系统调用号和参数放到约定位置;
- 执行专用陷入指令,CPU 切到内核态和内核入口;
- 入口代码保存用户寄存现场,内核验证参数和权限;
- 内核执行服务,必要时将进程阻塞;
- 结果写回约定寄存,恢复用户现场并返回用户态。
这是模式切换,不必然是进程切换。如果内核服务很快完成,返回的仍是原进程;只有调度器改选了另一进程,才需要保存和恢复两份 PCB 上下文。
一个“保护会付性能代价”的课件案例
课件用 Meltdown/Spectre 与 KPTI(Kernel Page Table Isolation)说明安全和性能的权衡。若用户态页表根本不映射内核数据,推测执行漏洞就更难借用户地址空间窥探内核;但系统调用/中断跨越用户态和内核态时需要切换页表,TLB 中的转换也可能失效,开销会上升。带地址空间标签的 TLB/PCID 等机制可以减少不必要的刷新。
这不是要求记某个 Linux 版本的跑分,而是理解:权限检查、隔离边界和快速缓存相互作用,修补安全边界可能改变热路径成本。
OS 内部怎么组织
课件介绍了多种结构:
- 单体内核:大量服务在同一内核地址空间,调用快,但隔离较弱;
- 分层结构:上层只依赖下层,边界清晰,但层次难以完美划分;
- 微内核:内核只保留中断、基本调度和 IPC,其他服务放到用户态服务器;
- 虚拟机:在硬件与多个客户 OS 之间再加一层资源抽象;
- 机制与策略分离:机制说明“能怎么做”,策略决定“这次选哪个”。
整门课反复出现最后一个思想:页面置换机制与置换算法、上下文切换机制与调度算法,都应尽量解耦。
课件中的 DOS 是边界松散的单体实例,传统 UNIX 以系统调用之下的内核服务组成单体,MINIX 展示微内核/用户态服务器,VM/370 和 VMware 展示虚拟机。Android、iOS、Windows 也都不是只用一种教科书结构:现实系统往往保留高性能的内核内服务,同时吸收分层、模块化、客户端—服务器和机制/策略分离的思想。
把这一讲连成一句话
操作系统利用处理器的特权级、中断和地址转换机制,把 CPU、内存和设备包装成进程、地址空间和文件等抽象,再用调度、同步和保护策略,让多个不可信程序方便、高效且相对安全地共享一台机器。