虚拟内存

进程

资源分配的基本单位。每个进程拥有独立的地址空间、文件描述符表、信号处理器等资源,进程之间彼此隔离。
进程的状态包括:创建、就绪、运行、阻塞、终止。
上下文切换
进程上下文切换需要保存和恢复的内容:
- CPU 寄存器(程序计数器 PC、栈指针 SP、通用寄存器等)
- 虚拟内存映射(页表基址寄存器,需刷新 TLB)
- 内核栈
- 进程控制块(PCB)中的状态信息
由于涉及页表切换和 TLB 刷新,进程切换的开销较大(通常在微秒级)。
进程间通信
进程拥有独立的地址空间,因此需要通过操作系统提供的 IPC 机制来通信:
| 方式 | 特点 | 适用场景 |
|---|---|---|
| 管道(Pipe) | 半双工,父子进程间使用 | 简单的单向数据流 |
| 命名管道(FIFO) | 半双工,无亲缘关系限制 | 不相关进程间通信 |
| 消息队列 | 有格式的消息,可按类型读取 | 结构化数据传递 |
| 共享内存 | 最快的 IPC 方式,需配合同步机制 | 大量数据交换 |
| 信号量(Semaphore) | 用于同步,控制对共享资源的访问 | 互斥与同步 |
| 信号(Signal) | 异步通知机制 | 事件通知(如 SIGKILL) |
| Socket | 支持不同主机间通信 | 网络通信 |
线程

CPU 调度的基本单位。同一进程内的线程共享地址空间、文件描述符和堆内存,但各自拥有独立的栈、程序计数器和寄存器组。
上下文切换
线程上下文切换只需保存和恢复:
- CPU 寄存器(PC、SP、通用寄存器)
- 线程栈指针
由于不涉及页表切换和 TLB 刷新(同进程内的线程共享地址空间),线程切换比进程切换快得多。
线程间通信
同一进程内的线程共享地址空间,可以直接读写共享变量,但需要同步机制来避免竞态条件:
- 互斥锁(Mutex):保证同一时刻只有一个线程访问临界区
- 读写锁(RWLock):允许多个读者并发,写者独占
- 条件变量(Condition Variable):让线程等待某个条件成立后再继续执行,配合互斥锁使用
- 信号量(Semaphore):控制并发访问数量
协程
运行在用户态的轻量级线程。协程的调度完全由用户程序控制,不需要陷入内核,因此切换开销极小。
与线程的关键区别:
| 线程 | 协程 | |
|---|---|---|
| 调度方 | 操作系统内核 | 用户程序 |
| 切换方式 | 抢占式 | 协作式(主动让出) |
| 栈大小 | 固定(通常 1-8 MB) | 动态增长(初始通常 2-8 KB) |
| 并发模型 | 抢占式多任务 | 协作式多任务 |
| 创建开销 | 较大(内核参与) | 极小(用户态完成) |
上下文切换
协程切换只需在用户态保存和恢复少量寄存器(PC、SP 及少量通用寄存器),不涉及系统调用和内核态切换,开销通常在纳秒级。
典型实现:Go 的 goroutine 采用 GMP 模型,将大量协程(G)多路复用到少量操作系统线程(M)上执行,由调度器(P)负责协程的分配。
调度

不同类型的系统有不同的调度目标,因此采用不同的调度算法。
批处理系统中的调度
目标:最大化吞吐量,最小化平均周转时间。没有用户交互,任务可以长时间占用 CPU。
- 先来先服务(FCFS):按到达顺序执行,简单但可能导致"护航效应"(convoy effect)——短任务被长任务阻塞
- 最短作业优先(SJF):优先执行预计运行时间最短的作业,平均等待时间最优但需要预知运行时间
- 最短剩余时间优先(SRTF):SJF 的抢占版本,新到达的短作业可以抢占当前作业
交互式系统中的调度
目标:最小化响应时间,保证公平性。用户期望每次操作都能快速得到反馈。
- 时间片轮转调度(Round Robin):每个进程分配一个时间片(通常 10-100 ms),用完即切换。时间片太小会导致切换开销过大,太大则退化为 FCFS
- 优先级调度:为每个进程分配优先级,高优先级先执行。需要防止低优先级进程饥饿(可通过老化机制解决)
- 多级反馈队列调度(MLFQ):设置多个优先级队列,新进程进入最高优先级队列;如果用完时间片则降到下一级队列,如果主动让出则保持当前级别。兼顾了响应时间和吞吐量
实时系统中的调度
目标:满足截止时间(deadline)。正确但迟到的结果等于错误结果。
- 硬实时:必须绝对保证在截止时间前完成(如航空控制、ABS 刹车系统)
- 软实时:偶尔错过截止时间可以容忍(如视频播放、音频流)
- 常用算法:速率单调调度(RMS)(静态优先级)、最早截止时间优先(EDF)(动态优先级)