虚拟内存

virtual memory

进程

process

资源分配的基本单位。每个进程拥有独立的地址空间、文件描述符表、信号处理器等资源,进程之间彼此隔离。

进程的状态包括:创建、就绪、运行、阻塞、终止。

上下文切换

进程上下文切换需要保存和恢复的内容:

  • CPU 寄存器(程序计数器 PC、栈指针 SP、通用寄存器等)
  • 虚拟内存映射(页表基址寄存器,需刷新 TLB)
  • 内核栈
  • 进程控制块(PCB)中的状态信息

由于涉及页表切换和 TLB 刷新,进程切换的开销较大(通常在微秒级)。

进程间通信

进程拥有独立的地址空间,因此需要通过操作系统提供的 IPC 机制来通信:

方式特点适用场景
管道(Pipe)半双工,父子进程间使用简单的单向数据流
命名管道(FIFO)半双工,无亲缘关系限制不相关进程间通信
消息队列有格式的消息,可按类型读取结构化数据传递
共享内存最快的 IPC 方式,需配合同步机制大量数据交换
信号量(Semaphore)用于同步,控制对共享资源的访问互斥与同步
信号(Signal)异步通知机制事件通知(如 SIGKILL)
Socket支持不同主机间通信网络通信

线程

thread

CPU 调度的基本单位。同一进程内的线程共享地址空间、文件描述符和堆内存,但各自拥有独立的栈、程序计数器和寄存器组。

上下文切换

线程上下文切换只需保存和恢复:

  • CPU 寄存器(PC、SP、通用寄存器)
  • 线程栈指针

由于不涉及页表切换和 TLB 刷新(同进程内的线程共享地址空间),线程切换比进程切换快得多。

线程间通信

同一进程内的线程共享地址空间,可以直接读写共享变量,但需要同步机制来避免竞态条件:

  • 互斥锁(Mutex):保证同一时刻只有一个线程访问临界区
  • 读写锁(RWLock):允许多个读者并发,写者独占
  • 条件变量(Condition Variable):让线程等待某个条件成立后再继续执行,配合互斥锁使用
  • 信号量(Semaphore):控制并发访问数量

协程

运行在用户态的轻量级线程。协程的调度完全由用户程序控制,不需要陷入内核,因此切换开销极小。

与线程的关键区别:

线程协程
调度方操作系统内核用户程序
切换方式抢占式协作式(主动让出)
栈大小固定(通常 1-8 MB)动态增长(初始通常 2-8 KB)
并发模型抢占式多任务协作式多任务
创建开销较大(内核参与)极小(用户态完成)

上下文切换

协程切换只需在用户态保存和恢复少量寄存器(PC、SP 及少量通用寄存器),不涉及系统调用和内核态切换,开销通常在纳秒级。

典型实现:Go 的 goroutine 采用 GMP 模型,将大量协程(G)多路复用到少量操作系统线程(M)上执行,由调度器(P)负责协程的分配。

调度

schedule

不同类型的系统有不同的调度目标,因此采用不同的调度算法。

批处理系统中的调度

目标:最大化吞吐量,最小化平均周转时间。没有用户交互,任务可以长时间占用 CPU。

  • 先来先服务(FCFS):按到达顺序执行,简单但可能导致"护航效应"(convoy effect)——短任务被长任务阻塞
  • 最短作业优先(SJF):优先执行预计运行时间最短的作业,平均等待时间最优但需要预知运行时间
  • 最短剩余时间优先(SRTF):SJF 的抢占版本,新到达的短作业可以抢占当前作业

交互式系统中的调度

目标:最小化响应时间,保证公平性。用户期望每次操作都能快速得到反馈。

  • 时间片轮转调度(Round Robin):每个进程分配一个时间片(通常 10-100 ms),用完即切换。时间片太小会导致切换开销过大,太大则退化为 FCFS
  • 优先级调度:为每个进程分配优先级,高优先级先执行。需要防止低优先级进程饥饿(可通过老化机制解决)
  • 多级反馈队列调度(MLFQ):设置多个优先级队列,新进程进入最高优先级队列;如果用完时间片则降到下一级队列,如果主动让出则保持当前级别。兼顾了响应时间和吞吐量

实时系统中的调度

目标:满足截止时间(deadline)。正确但迟到的结果等于错误结果。

  • 硬实时:必须绝对保证在截止时间前完成(如航空控制、ABS 刹车系统)
  • 软实时:偶尔错过截止时间可以容忍(如视频播放、音频流)
  • 常用算法:速率单调调度(RMS)(静态优先级)、最早截止时间优先(EDF)(动态优先级)