📚 操作系统知识完全总结(11章全)

本文基于 11 章操作系统教材编写,面向零基础学习者
每个知识点配有通俗解释 + 生活类比 + 举例说明


目录

  1. [第 1 章 操作系统引论]
  2. [第 2 章 进程和线程]
  3. [第 3 章 调度]
  4. [第 4 章 存储管理]
  5. [第 5 章 文件系统]
  6. [第 6 章 输入输出管理]
  7. [第 7 章 用户接口服务]
  8. [第 8 章 死锁]
  9. [第 9 章 嵌入式操作系统]
  10. [第 10 章 分布式系统和云计算]
  11. [第 11 章 安全与保护机制]

第 1 章 操作系统引论

1.1 什么是操作系统?

通俗理解: 操作系统(OS)是电脑的"大管家"——它管理所有硬件(CPU、内存、硬盘等),同时为应用程序(微信、浏览器等)提供运行环境。

核心定义: 操作系统是控制和管理计算机硬件与软件资源的系统软件。

生活中的类比:

想象一个餐厅:操作系统就是餐厅经理,硬件(CPU、内存等)是厨房设备,应用程序(App)是厨师和服务员。经理不直接做菜,但协调一切——分配炉灶、安排人员、确保不冲突。

1.2 操作系统的四大角色

角色 通俗解释 例子
资源管理者 管理 CPU、内存、硬盘等硬件资源 决定哪个程序先用 CPU
用户接口 提供人与计算机交互的方式 鼠标点击、键盘输入、触屏
程序执行环境 让应用程序能在计算机上运行 你打开 Word 时,OS 帮它分配内存
服务提供者 提供文件读写、网络通信等功能 保存文件、发送网络请求

1.3 操作系统的发展历史

第一代 (1940s-1950s):无操作系统 → 插拔线路、纸带输入
     ↓
第二代 (1950s-1960s):批处理系统 → 一次提交一批任务
     ↓
第三代 (1960s-1970s):多道程序系统 → 内存中同时有多道程序
     ↓
第四代 (1980s至今):分时/个人计算机 → Windows, UNIX, Linux, macOS
     ↓
现代:移动/嵌入式/分布式/云操作系统

1.4 操作系统的分类

类型 特点 例子
批处理系统 批量执行任务,用户无法交互 早期 IBM 大型机
分时系统 多用户同时使用,轮流分配时间片 UNIX、Linux
实时系统 必须在严格时限内响应 飞机自动驾驶、导弹控制
个人系统 单用户使用,交互性强 Windows、macOS
网络系统 面向网络环境,管理网络资源 Windows Server
分布式系统 多台计算机协同工作 Google 搜索系统
嵌入式系统 内置在设备中,专用性强 手机、智能手表、路由器

小贴士: 我们日常用的 Windows/macOS 是个人操作系统 + 分时系统的结合体。手机系统(iOS/Android)本质上属于嵌入式操作系统

1.5 操作系统的核心功能

  1. 进程管理 — 管理正在运行的程序
  2. 存储管理 — 分配和回收内存
  3. 文件管理 — 管理硬盘上的文件和目录
  4. 设备管理 — 管理键盘、鼠标、打印机等设备
  5. 用户接口 — 提供图形界面或命令行

1.6 操作系统的结构

(1)简单结构(单体内核)

  • 所有功能都放在内核中
  • 例子:MS-DOS、早期 UNIX
  • 优点:效率高
  • 缺点:一个模块崩溃,整个系统崩溃

(2)分层结构

  • 操作系统按层次划分,每层只与相邻层交互
  • 优点:易于维护和调试
  • 例子:THE 操作系统

(3)微内核结构

  • 内核只保留最基本的功能(进程通信、基本调度)
  • 其他功能(文件系统、设备驱动)在用户空间运行
  • 优点:稳定性高、扩展性好
  • 例子:Minix、QNX

(4)模块化结构

  • 内核可以动态加载和卸载模块
  • 现代 Linux 使用此结构

(5)虚拟机结构

  • VMM(虚拟机监视器)在硬件之上运行,创建多个虚拟机
  • 例子:VMware、VirtualBox、KVM

第 2 章 进程和线程

2.1 进程的概念

通俗理解: 进程就是"正在执行的程序"。

程序是静态的(像一个菜谱),进程是动态的(像正在照着菜谱做菜的过程)。

举例:

  • 双击打开微信 → 微信程序变成一个"进程"
  • 同时打开浏览器、Word、微信 → 三个进程在同时运行

2.2 进程的三态模型

       ┌──────────┐
       │  就绪态   │ ◄────────────┐
       └────┬─────┘              │
            │ (调度选中)         │ (I/O 完成/事件发生)
            ▼                    │
       ┌──────────┐    I/O请求   ┌──────────┐
       │  运行态   │ ──────────► │  阻塞态   │
       └──────────┘              └──────────┘
            │
            │ (时间片用完)
            ▼
       ┌──────────┐
       │  就绪态   │
       └──────────┘
三种基本状态:
状态 通俗解释 CPU 能否继续执行
运行态(Running) 正在使用 CPU
就绪态(Ready) 万事俱备,只等 CPU 等 CPU 分配
阻塞态(Blocked/Wait) 在等某件事完成 ✗ (等事件完成)

生活的类比: 去银行办事

  • 运行态:你正在柜台办理
  • 就绪态:你在排队等着,轮到你了就上
  • 阻塞态:需要填表但笔没墨水了,只能等着
五种状态模型(扩展):
          ┌───────┐
          │ 新建态 │  ← 进程被创建
          └───┬───┘
              ▼
          ┌───────┐       ┌──────────┐
          │ 就绪态 │ ◄───► │  运行态   │
          └───┬───┘       └────┬─────┘
              │                │
              ▼                ▼
          ┌───────┐       ┌──────────┐
          │ 阻塞态 │       │ 终止态   │
          └───────┘       └──────────┘

2.3 进程控制块(PCB)

核心概念: 操作系统为每个进程建立一个 PCB,就像每个人的"身份证"。

PCB 中记录了哪些信息?

信息类型 内容
进程标识 PID(进程ID)、PPID(父进程ID)、UID(用户ID)
处理机状态 寄存器值、程序计数器(PC)、状态字
进程调度信息 状态、优先级、等待时间
内存管理信息 页表/段表指针
资源清单 打开的文件列表、使用设备信息

PCB 的组织方式:

  • 链表方式 — 按状态将 PCB 连成不同链表(就绪队列、阻塞队列等)
  • 索引方式 — 建立索引表

2.4 进程的上下文切换

概念: CPU 从一个进程切换到另一个进程的过程。

切换步骤:

  1. 保存当前进程的上下文(寄存器、程序计数器等)
  2. 更新 PCB
  3. 选择新进程
  4. 恢复新进程的上下文
  5. 执行新进程

上下文切换是有代价的(需要时间),所以不是切换得越频繁越好。

2.5 进程的创建和终止

创建原因:

  • 系统初始化
  • 用户请求(双击运行程序)
  • 正在运行的进程创建子进程(如 Chrome 创建新标签页)
  • 批处理作业启动

终止原因:

  • 正常完成
  • 发生错误
  • 被其他进程终止

UNIX/Linux 中的 fork()

#include <unistd.h>
#include <stdio.h>

int main() {
    pid_t pid = fork();  // 创建子进程
    
    if (pid < 0) {
        fprintf(stderr, "Fork Failed");
        return 1;
    }
    else if (pid == 0) {
        // 子进程代码
        execlp("/bin/ls", "ls", NULL);
    }
    else {
        // 父进程代码
        wait(NULL);  // 等待子进程完成
        printf("Child Complete");
    }
    return 0;
}

fork() 一次调用,两次返回——父进程返回子进程 PID,子进程返回 0。

2.6 进程间通信(IPC)

方式 通俗解释 特点
管道(Pipe) 一个进程写,另一个读 单向、一般适用于父子进程
消息队列 进程发送/接收消息 双向、无需同步
共享内存 多个进程共享一块内存 速度最快,需同步机制
信号量 像红绿灯控制访问 用于同步,不是传数据
套接字(Socket) 网络通信 可跨机器通信

💡 生活类比:

  • 管道 = 两个人传纸条
  • 消息队列 = 互相写信
  • 共享内存 = 共用一块白板
  • 信号量 = 红绿灯
  • Socket = 打电话

2.7 线程的概念

通俗理解: 线程是进程中的"子任务"。

进程 = 工厂,线程 = 工厂里的工人

进程与线程的区别
对比项 进程 线程
资源开销 大(独立内存空间) 小(共享进程内存)
切换速度 慢(需要切换地址空间) 快(共享地址空间)
通信方式 IPC(较复杂) 直接读写共享数据
独立性 一个崩溃不影响其他进程 一个崩溃可能影响同进程所有线程

举例: 打开浏览器是一个进程,内部有多个线程:

  • 线程 1:渲染页面
  • 线程 2:下载图片
  • 线程 3:响应用户点击
用户级线程 vs 内核级线程
对比 用户级线程 内核级线程
管理方式 用户空间管理 操作系统管理
切换速度 快(无需系统调用) 慢(需要陷入内核)
阻塞影响 一个线程阻塞→整个进程阻塞 一个线程阻塞不影响其他线程
并行性 不能利用多核 能利用多核

2.8 多线程模型

多对一模型: 多个用户线程映射到一个内核线程

  • 不能利用多核

一对一模型: 每个用户线程映射到一个内核线程

  • 能利用多核,但创建线程成本高

多对多模型: 多个用户线程映射到多个内核线程

  • 结合了两者的优点

第 3 章 调度

3.1 什么是调度?

通俗理解: 当多个进程都想使用 CPU 时,操作系统得决定"谁先用、用多久"——这就是调度

就像一家人排队用一台电脑——操作系统像排班表,决定每个人用多久、谁先用。

3.2 调度的层次

层次 名称 作用 频率
高级调度(长程) 作业调度 哪些作业进入内存 慢(秒/分钟级)
中级调度(中程) 交换调度 进程在内存与磁盘间交换 中等
低级调度(短程) CPU 调度 哪个进程使用 CPU 极快(毫秒级)

3.3 调度的目标

  • 公平性 — 每个进程都能得到 CPU 时间
  • 响应时间短 — 交互式操作反馈快
  • 吞吐量大 — 单位时间完成的任务多
  • CPU 利用率高 — CPU 不闲置
  • 平衡资源 — 让系统中的各类资源都能被有效利用

3.4 调度方式

非抢占式(Non-preemptive): 进程一旦获得 CPU,除非主动放弃,否则一直运行。

  • 适合:批处理系统

抢占式(Preemptive): 操作系统可以强制暂停正在运行的进程,把 CPU 分配给其他进程。

  • 适合:分时系统、实时系统

3.5 关键性能指标

周转时间 = 进程完成时间 - 进程到达时间
等待时间 = 在就绪队列中等待的总时间
响应时间 = 提交请求到第一次响应的时间
CPU利用率 = CPU 忙的时间 / 总时间
吞吐量 = 单位时间完成的进程数

3.6 常见的调度算法

(1)先来先服务(FCFS)

原理: 谁先到达谁先用(像银行排队)。

优点 缺点
简单、公平 短任务可能被长任务阻塞
容易实现 不适合交互式系统

举例:

进程 A(需要 10 分钟)先到,进程 B(需要 1 分钟)后到
→ A 执行 10 分钟,B 再执行 1 分钟
→ 平均等待时间 = (0 + 10) / 2 = 5 分钟
→ B 只需要 1 分钟,却等了 10 分钟!不合理。

(2)短作业优先(SJF)

原理: 先执行需要时间最短的任务。

优点 缺点
平均等待时间最小(理论上最优) 长任务可能"饿死"
适合批处理系统 需要预先知道运行时间

举例:

进程:A(6ms)、B(3ms)、C(1ms)
SJF 顺序:C(1ms) → B(3ms) → A(6ms)
平均等待时间 = (0 + 1 + 4) / 3 ≈ 1.67ms ✅(远优于 FCFS)

(3)最短剩余时间优先(SRTN)
  • SJF 的抢占式版本
  • 每次有新进程到达时,比较剩余时间,选最短的继续
  • 适用于交互式环境
(4)时间片轮转(Round Robin)

原理: 每个进程轮流使用 CPU,每次用固定时间(时间片)。

关键参数: 时间片大小

  • 时间片太大 → 退化为 FCFS
  • 时间片太小 → 上下文切换开销太大

举例:

时间片 = 4ms,进程到达顺序:A(6ms)、B(3ms)、C(1ms)
执行顺序:A(4ms) → B(3ms) → C(1ms) → A(2ms)
响应时间:A=0, B=4, C=7(都很快得到响应 ✅)

(5)优先级调度

原理: 每个进程分配优先级,优先级高的先执行。

静态优先级: 创建时确定,不变
动态优先级: 随进程行为变化(如等待越久优先级越高,防止"饥饿")

(6)多级反馈队列

原理: 设置多个就绪队列,各队列使用不同调度策略和优先级。

                             ┌────────────────┐
          ┌──────────────────►│ 队列1(优先级最高)│◄── 时间片 = 8ms
          │                   └───────┬────────┘
          │ 未完成                  │
          │                   ┌──────▼────────┐
          │──────────────────►│ 队列2          │◄── 时间片 = 16ms
          │ 未完成             └───────┬────────┘
          │                          │
          │                   ┌──────▼────────┐
          └──────────────────►│ 队列3(最低)   │◄── FCFS
                              └────────────────┘

这是现代操作系统最常用的调度算法(Windows、Linux 都在用)!

3.7 作业调度(JCB)

作业控制块(JCB) — 记录作业信息的结构,类似进程的 PCB。

作业调度算法:

  • 先来先服务
  • 短作业优先
  • 优先级调度

3.8 UNIX/Linux 调度

  • Linux 使用 完全公平调度器(CFS)
  • 基于优先级 + 运行时间动态调整
  • 确保所有进程公平使用 CPU

第 4 章 存储管理

4.1 存储管理概述

核心问题: 内存有限(比如 8GB),但多个程序都想用,怎么分配?

四个主要目标:

  1. 内存分配 — 给进程分配内存空间
  2. 地址转换 — 把程序中的逻辑地址转为物理地址
  3. 内存保护 — 一个进程不能访问另一个进程的内存
  4. 内存扩充 — 让有限的内存运行更大的程序

💡 类比: 存储管理像图书馆管理——分配书架、找书、防止书被乱拿、用电子书架扩充容量。

4.2 地址的概念

地址类型 定义 通俗理解
物理地址 内存中真实的物理单元编号 真实的门牌号
逻辑地址(虚拟地址) 程序中使用的地址 虚构的门牌号

程序看到的地址是"假"的,操作系统负责把假地址转成真地址。

4.3 地址绑定(Binding)

发生在不同阶段的地址绑定:

阶段 绑定方式 特点
编译时 绝对地址 起始地址已知,否则要重新编译
加载时 可重定位地址 加载时修改地址
运行时 动态地址映射 运行时通过硬件转换(最灵活)

4.4 内存分配方式

4.4.1 连续分配

固定分区:

  • 内存预先分成固定大小的区域
  • 简单但浪费(内部碎片)

动态分区:

  • 按需分配内存大小
  • 容易出现外部碎片

碎片问题:

外部碎片:像停车场停了很多小车,剩下很多小空位——加起来很大,但停不了一辆大车。

四种分区分配算法:

算法 策略 特点
首次适应(First-fit) 找第一个够用的分区 速度最快
最佳适应(Best-fit) 找刚刚够用的分区 减少大块浪费
邻近适应(Next-fit) 从上一次找到的位置开始找 分配更均匀
最差适应(Worst-fit) 找最大的分区 留下较均匀的空隙
4.4.2 非连续分配——分页

核心思想: 把内存分成固定大小的"页框"(通常 4KB),程序的虚拟空间也分成同样大小的"页"。

关键概念:

  • 页(Page) — 程序中的固定大小块(虚拟空间)
  • 页框/帧(Frame) — 内存中的固定大小块(物理空间)
  • 页表(Page Table) — 记录页→页框的映射关系
  • TLB(快表/转换后备缓冲器) — 页表的"硬件缓存",加速地址转换

虚拟地址结构(假设 32 位,4KB 页):

┌──────────────┬─────────────┐
│  页码 p      │  页内偏移 d  │
│  (20位)      │  (12位)     │
└──────────────┴─────────────┘

地址转换过程:

逻辑地址 A → p = INT(A/L), d = A MOD L
→ 查页表得到页框号 f
→ 物理地址 = f × L + d

💡 类比: 就像查字典——页码(页号)告诉你在哪块区域,具体第几个字(偏移)是具体位置。

TLB 加速:

  • 有 TLB 时:20ns(TLB查询) + 100ns(内存访问) = 120ns
  • 无 TLB 时:100ns(查页表) + 100ns(内存访问) = 200ns
  • TLB 命中率 ≥ 98% → 性能提升显著
4.4.3 分段存储管理

思路: 按程序的逻辑结构分段:代码段、数据段、堆栈段等。

虚拟地址结构: 段号 + 段内偏移

段表: 记录每段的基地址和段长

与分页的对比:

对比 分页 分段
划分依据 固定大小(硬件决定) 逻辑结构(用户可见)
大小 固定(如 4KB) 可变
优点 无外部碎片 符合程序逻辑,便于共享和保护
4.4.4 段页式存储管理

结合分页和分段: 先分段 → 每段再分页

  • 分段对用户友好(按逻辑划分)
  • 分页对系统友好(避免外部碎片)
  • 代价:地址转换需要两次查表

4.5 虚拟内存(超级重要!)

通俗理解: 让程序"以为"自己有超大的内存,实际上部分数据在硬盘上。

就像你在一张桌子上看书,书的内容远远超过桌子大小。你只把当前看的几页放在桌上,其他页放在抽屉里。想看下一页时,从抽屉取出,放回不需要的页。这就是虚拟内存!

工作原理
┌──────────────────┐
│   虚拟地址空间     │  程序认为它有超大内存
│  (比如 4GB)       │
└────────┬─────────┘
         │
         ▼ 地址转换(分页)
    ┌────┴────┐
    │ 在内存吗? │
    └────┬────┘
    是↙    ↘否
   继续    缺页中断
           → 从硬盘加载页到内存
           → 如果内存满,先换出一些页
           → 更新页表
           → 继续执行
请求分页

程序访问的页不在内存中时发生缺页中断(Page Fault)

处理流程:

  1. CPU 捕获缺页异常
  2. 操作系统找到需要加载的页在硬盘的位置
  3. 如果内存有空闲 → 直接从硬盘读入
  4. 如果内存已满 → 先执行页面置换
  5. 更新页表
  6. 重新执行导致缺页的指令
页面置换算法
算法 策略 特点
FIFO 先进先出 简单但可能换出常用页(Belady异常)
LRU(最近最少使用) 换出最久没有访问的页 效果好,实现成本高
Clock(时钟) 近似 LRU 硬件支持较少,常用
最佳置换(OPT) 换出未来最久不用的页 理论最优,无法实现
页框分配策略
  • 固定分配 — 每个进程分配固定数量的页框
  • 可变分配 — 根据进程需求动态调整页框数量

全局置换 vs 局部置换:

  • 全局置换 — 缺页时从所有进程中选择换出页
  • 局部置换 — 缺页时只从自己的进程中换出
抖动(Thrashing)

现象: 进程频繁缺页,大部分时间花在换入换出上,CPU 利用率极低。

原因: 进程没有获得足够的页框(工作集太大)。

解决方案:

  • 工作集模型(保证每个进程有足够的页框)
  • 控制多道程序度(不让太多进程同时跑)
内存映射文件

概念: 将文件直接映射到进程的虚拟地址空间,像访问内存一样访问文件。

优点: 简化文件操作,多个进程可以共享映射。

4.6 内核内存分配

  • 伙伴系统(Buddy System) — 分配 2 的幂次大小的内存块
  • slab 分配器 — 为内核对象创建专用缓存(Linux 使用)

4.7 Linux 内存管理特点

  • 使用三级/四级页表(适应 64 位)
  • 支持交换(swap)
  • OOM Killer — 内存耗尽时自动杀死进程
  • 使用 MMU(内存管理单元) 进行硬件地址转换

第 5 章 文件系统

5.1 什么是文件和文件系统

通俗理解: 文件系统是操作系统的"档案柜管理方法"。

概念 定义 类比
文件(File) 相关信息的集合,存储在硬盘上 一本书
文件系统(File System) 管理文件的一套机制 图书馆分类体系

5.2 文件的属性

属性 说明 例子
文件名 用户标识文件 report.docx
标识符 系统内部唯一编号(如 i-node) 345678
类型 文件的种类 文本、可执行、图片
位置 在设备上的物理位置 扇区号
大小 文件占用空间 1024 字节
保护信息 谁可以读/写/执行 rwxr-xr--
时间戳 创建、修改、访问时间 2024-01-15 10:30

5.3 文件类型

按用途分类:

类别 扩展名
可执行文件 .exe, .com, .bin, .out
目标文件 .o, .obj
源程序 .c, .java, .py, .asm
批处理/脚本 .bat, .sh, .bash
文本文件 .txt, .doc, .tex, .rtf
库文件 .lib, .a, .so, .dll
多媒体 .jpg, .png, .mp3, .mp4
归档/压缩 .zip, .tar, .rar

按内部结构分类:

  • 无结构文件 — 字节流(如 UNIX 普通文件)
  • 记录文件 — 由固定或可变长度的记录组成
  • 索引文件 — 带有索引以便快速访问

5.4 文件的操作

基本操作:

create(创建) → open(打开) → read/write(读写)
→ seek(定位) → close(关闭) → delete(删除)

其他操作:

  • append(追加写入)
  • rename(重命名)
  • get_attributes(获取属性)/ set_attributes(设置属性)

5.5 文件的逻辑结构

结构 特点 例子
有结构文件 由记录组成 数据库文件
无结构文件 字节流 普通文本文件
堆结构 按到达顺序 日志文件
顺序结构 按关键字段排序 电话簿
索引结构 带索引表 字典

5.6 文件目录

5.6.1 文件控制块(FCB)

FCB(File Control Block) — 每个文件的"身份证",包含文件的所有信息。

UNIX 中的 i-node(索引节点):

  • 文件名存在目录中,文件信息存在 i-node 中
  • i-node 包含文件属性和数据块指针
  • 目录项:文件名 + i-node 号

FCB 包含的内容:

  • 文件名
  • 文件类型
  • 文件大小
  • 文件位置(硬盘物理地址)
  • 权限信息
  • 时间戳
  • 所属用户/组
5.6.2 目录结构的发展
① 单级目录
   ┌─────────────┐
   │ 文件A 文件B  │  ← 所有文件都在同一层
   │ 文件C 文件D  │
   └─────────────┘
   ❌ 不能重名、组织混乱

② 二级目录
   ┌───────────────┐
   │ 用户1目录 用户2│
   │ ┌─────┐ ┌───┐ │
   │ │A B C│ │A D│ │  ← 不同用户目录可以重名
   │ └─────┘ └───┘ │
   └───────────────┘

③ 树形目录(最常用 ✓)
   / (根目录)
   ├── usr/
   │   ├── bin/
   │   ├── lib/
   │   └── local/
   ├── home/
   │   ├── user1/
   │   │   ├── file1.txt
   │   │   └── file2.txt
   │   └── user2/
   └── etc/

路径类型:

  • 绝对路径:从根开始 /home/user1/file.txt
  • 相对路径:从当前目录开始 ./file.txt../data/file.txt

Windows 用反斜杠 \,UNIX/Linux 用正斜杠 /

5.6.3 目录的操作
  • create/detele — 创建/删除目录
  • opendir/closedir — 打开/关闭目录
  • readdir — 读取目录项
  • rename — 重命名
  • link/unlink — 链接/取消链接
5.6.4 文件共享

硬链接(Hard Link): 多个目录项指向同一个 i-node

  • 删除一个不影响其他
  • 不能跨文件系统

软链接/符号链接(Symbolic Link): 一个特殊文件指向另一个文件的路径

  • 类似 Windows 的快捷方式
  • 可以跨文件系统

5.7 文件的物理结构

组织方式 工作原理 优点 缺点
连续分配 文件存储在连续的块 读取快 碎片多、扩展难
链接分配 每个数据块指向下一个 无外部碎片 随机访问慢
索引分配 索引块记录所有数据块位置 随机访问快 小文件浪费
UNIX 混合索引 多级索引结合直接/间接块 兼顾大小文件 实现复杂

UNIX 混合索引(经典的 i-node 结构):

i-node
├── 10 个直接块指针     → 文件 ≤ 40KB(4KB/块)
├── 1 个一级间接块指针  → 可访问 256 个块
├── 1 个二级间接块指针  → 可访问 256² 个块
└── 1 个三级间接块指针  → 可访问 256³ 个块

5.8 空闲空间管理

方法 说明
位图(Bitmap) 每位表示一个块是否空闲
空闲链表 把空闲块链接起来
成组链接法 UNIX 使用,组合块和索引

5.9 文件系统的可靠性

备份策略:

  • 全量备份
  • 增量备份(只备份修改的文件)
  • 差异备份

日志文件系统(Journaling):

  • 写操作先记录到日志
  • 崩溃后可通过日志恢复
  • 例子:NTFS、ext3/ext4

5.10 常见文件系统

文件系统 平台 特点
FAT32 Windows 简单、兼容性好,不支持 ≥4GB 文件
NTFS Windows 支持大文件、权限、加密、日志
ext4 Linux 日志文件系统,性能好
APFS macOS 优化 SSD,快照功能
ZFS Solaris/Linux 超大容量,数据完整性

第 6 章 输入输出管理

6.1 I/O 设备概述

I/O 设备 — 计算机与外界交互的硬件设备(键盘、鼠标、硬盘、打印机等)。

6.1.1 设备分类

按传输速度:

级别 速度 例子
低速 ≤ 1000 字节/秒 键盘、鼠标
中速 1000~1000000 字节/秒 打印机、扫描仪
高速 ≥ 1MB/秒 磁盘、显示器、网卡

按传输单位:

类型 特点 例子
块设备(Block Device) 以数据块为单位,可寻址 硬盘、U盘、SSD
字符设备(Character Device) 以字符流为单位,不可寻址 键盘、打印机、鼠标
6.1.2 磁盘的基本结构
                    ┌──────┐
    磁头            │ 扇区 │ ← 最小的存储单位(512B~4KB)
     ↓              ├──────┤
  ┌────┐            │      │
  │ 磁道│← 同心圆环  │ 磁道 │
  │    │            │      │
  │ 柱面│← 所有盘面  └──────┘
  │    │   同一磁道   扇区
  └────┘

磁盘访问时间 = 寻道时间 + 旋转延迟 + 传输时间

  • 寻道时间:磁头移动到目标磁道的时间(主要时间消耗)
  • 旋转延迟:目标扇区旋转到磁头下方的时间
  • 传输时间:读取数据的时间
6.1.3 磁盘调度算法
算法 策略 特点
FCFS(先来先服务) 按请求顺序 简单,但寻道时间长
SSTF(最短寻道时间优先) 选最近的请求 响应快,但可能"饥饿"
SCAN(电梯算法) 沿一个方向扫描到头再折返 公平性好
C-SCAN(循环扫描) 单向扫描,快速返回起点 等待时间更均匀

💡 电梯算法类比: 电梯不会为了按了 15 楼的人而改变方向——它会按照当前方向一直走到尽头,再折返。

6.2 I/O 控制方式

① 程序查询方式(Programmed I/O)

原理: CPU 不断检查设备状态——“设备准备好了吗?”

CPU: 好了吗?→ 设备: 没好 → CPU: 好了吗?→ 设备: 没好 → ... → 设备: 好了!
  • ❌ CPU 被占用,效率极低

类比: 你一直盯着电饭煲看饭熟了没有——没法做其他事。

② 中断控制方式(Interrupt-driven I/O)

原理: CPU 发起 I/O 操作后去做其他事,设备完成后发送中断信号通知 CPU。

CPU 发起 I/O → 继续做其他事 ─┐
                             │
设备完成 → 发送中断信号 → CPU 暂停当前工作
                              ↓
                    CPU 处理中断 → 恢复之前的工作
  • ✅ CPU 利用率大大提高

类比: 电饭煲做好饭后"叮"一声通知你,你可以利用等待时间做其他事。

中断处理流程:

  1. 设备发出中断信号
  2. CPU 完成当前指令
  3. 保存当前状态(程序计数器、寄存器等)
  4. 确定中断来源
  5. 执行中断处理程序
  6. 恢复状态,继续执行

中断向量表: 存储各种中断对应的处理程序入口地址

中断向量号 0 → 时钟中断
中断向量号 1 → 键盘中断
中断向量号 2 → 磁盘中断
中断向量号 3 → 软件中断
...
③ DMA 方式(Direct Memory Access)

原理: DMA 控制器直接在设备和内存之间传输数据,无需 CPU 参与数据搬运。

数据传输时:
CPU → 做其他事(计算)
DMA控制器 → 负责 I/O 数据传输
设备 ↔ DMA ↔ 内存
完成后 → DMA 发送中断通知 CPU
  • ✅ 极大提高效率,解放 CPU

类比: 你(CPU)安排快递员(DMA)去搬东西,你继续做自己的事。

DMA 传输步骤:

  1. CPU 设置 DMA 寄存器(数据源地址、目标地址、字节数)
  2. CPU 通知 DMA 开始传输
  3. DMA 控制总线进行数据传输
  4. 传输完成后,DMA 发送中断通知 CPU
④ 通道控制方式
  • 使用专门的 I/O 通道处理器 管理 I/O
  • 通道有自己的指令,可以执行复杂的 I/O 程序
  • CPU 只需发出一个 I/O 指令,其余由通道完成

是大型机(IBM 370)中使用的高级 I/O 方式。

6.3 中断机制

中断(Interrupt) — 设备通知 CPU 的一种机制。

中断类型:

中断类型 来源 例子
硬件中断 外部设备 键盘按下、磁盘完成
软件中断(陷阱) 程序主动触发 系统调用请求
异常 CPU 内部 除零错误、缺页

中断优先级:

  • 多个中断可同时发生时,优先级高的先处理
  • 高优先级中断可以打断低优先级中断的处理

典型中断优先级(从高到低):

  1. 机器故障中断(如电源故障)
  2. 时钟中断
  3. 磁盘中断
  4. 网络中断
  5. 键盘/鼠标中断

6.4 缓冲技术

缓冲区: 内存中用于临时存放 I/O 数据的区域。

为什么要缓冲?

  • 协调 CPU 和 I/O 设备的速度差异
  • 减少中断次数
  • 解决数据粒度不匹配问题

缓冲方式:

  • 单缓冲
  • 双缓冲
  • 循环缓冲
  • 缓冲池

举例: 你打字很快,但打印机打印很慢。系统把要打印的内容存在缓冲区,一次性发给打印机。你继续打字,打印机慢慢打。

6.5 SPOOLing 技术

SPOOLing(Simultaneous Peripheral Operation On-Line) — 同时的外围设备联机操作。

通俗理解: 用磁盘模拟慢速设备,实现"虚拟设备"。

工作原理:

多个程序同时 "打印"
    ↓
输出到磁盘缓冲区(输入井/输出井)
    ↓
SPOOLing 守护进程依次发送到真实打印机

典型应用:打印机共享

  • 多个程序可以同时"打印"(实际输出到磁盘)
  • SPOOLing 系统依次把缓冲区的内容送到真实打印机
  • 用户无需等待其他程序完成打印

6.6 I/O 软件层次结构

用户态
┌────────────────────┐
│ 用户 I/O 库函数     │ ← printf(), scanf(), read(), write()
├────────────────────┤
│ 用户进程            │
├────────────────────┤
核心态
├────────────────────┤
│ 设备无关的 I/O 软件  │ ← 缓冲、错误处理、分配
├────────────────────┤
│ 设备驱动程序         │ ← 与硬件相关的代码
├────────────────────┤
│ 中断处理程序         │ ← 处理设备中断
├────────────────────┤
│ 硬件                 │ ← 实际设备
└────────────────────┘

6.7 设备驱动程序

  • 每种设备都有对应的驱动程序
  • 驱动程序是操作系统与硬件设备之间的"翻译官"
  • 统一 I/O 接口,屏蔽设备差异

类比: 同样的 USB 接口,插入不同设备需要装不同驱动——就像插座标准化,但电器内部各不相同。


第 7 章 用户接口服务

7.1 用户接口的类型

操作系统提供两种用户接口:

① 命令行接口(CLI)→ 输入命令 → 如:ls, cd, mkdir
② 图形用户接口(GUI)→ 点击图标 → 如:Windows, macOS

7.2 系统调用

系统调用(System Call) — 程序请求操作系统服务的方式。

通俗理解: 应用程序不能直接操作硬件,必须通过"系统调用"请求操作系统帮忙。

就像你不能直接去厨房拿菜(直接访问硬件),而是通过服务员(系统调用)下单。

系统调用的分类
类别 系统调用 说明
进程控制 fork(), exit(), wait(), exec() 创建/终止/等待进程
文件操作 open(), read(), write(), close() 读写文件
设备管理 ioctl() 控制设备
信息维护 getpid(), alarm(), sleep() 获取/设置系统信息
通信 pipe(), shmget(), socket() 进程间通信
系统调用的执行过程
① 应用程序调用库函数 (如 printf())
    ↓
② 库函数准备参数
    ↓
③ 执行陷阱指令 (trap),从用户态切换到核心态
    ↓
④ 操作系统内核根据系统调用号查找 sysent[] 表
    ↓
⑤ 执行对应的内核服务函数
    ↓
⑥ 返回结果,从核心态切回用户态

系统调用表(sysent):

系统调用号 0 → nosys(无效调用)
系统调用号 1 → exit
系统调用号 2 → fork
系统调用号 3 → read
系统调用号 4 → write
系统调用号 5 → open
系统调用号 6 → close
系统调用的参数传递
  1. 通过寄存器传递(最快,但参数数量有限)
  2. 通过内存块传递(参数多时使用)
  3. 通过堆栈传递

7.3 Shell(命令行解释器)

Shell — 用户和操作系统之间的命令行接口。

常见 Shell 类型
Shell 名称 特点
sh(Bourne Shell) UNIX 最早的 Shell
bash(Bourne Again Shell) Linux 默认,功能强大
csh(C Shell) 类似于 C 语言语法
ksh(Korn Shell) 兼容 sh,功能更丰富
Shell 的功能
  1. 命令解释 — 解析用户输入的命令
  2. 命令执行 — 创建子进程执行命令
  3. I/O 重定向>(输出重定向)、<(输入重定向)
  4. 管道| 将一个命令的输出作为另一个命令的输入
  5. 环境管理 — 设置环境变量
  6. 编程 — 支持脚本编程
Shell 的工作流程
Shell 显示提示符 $ → 用户输入命令
    ↓
Shell 解析命令(分解为命令名 + 参数)
    ↓
Shell 创建子进程(fork)
    ↓
子进程执行命令(exec)
    ↓
Shell 等待子进程完成(wait)
    ↓
Shell 显示下一个提示符 $

这不是 Windows 命令提示符(cmd)吗?
原理一样,但语法不同。cmd 是 Windows 的命令解释器。

7.4 Shell 编程示例

简单脚本 ex1.sh

#!/bin/bash
date          # 显示日期
pwd           # 显示当前目录
cd ..         # 切换到上级目录

带逻辑的脚本 ex2.sh

#!/bin/bash
# 如果没有参数,则列出当前目录
# 否则,列出每个子目录
if test $# = 0
then
    ls .
else
    for i
    do
        ls -l $i | grep '^d'
    done
fi

7.5 图形用户界面(GUI)

GUI 的发展里程碑:

  • 1984 年:Macintosh 首次普及 GUI
  • 1990 年:Windows 3.0
  • 1995 年:Windows 95(开始菜单)
  • 现在:Windows 11、macOS、GNOME、KDE
X Window 系统

特点: 独特的客户端-服务器架构

  • 应用程序(客户端)和显示(服务器)分离
  • 可以在远程计算机上显示图形界面
  • 网络透明性

X Window 架构:

┌───────────────┐     网络       ┌───────────────┐
│  X Server     │ ◄──────────►  │  X Client     │
│  (本机显示)   │               │  (远程程序)   │
└───────────────┘               └───────────────┘
GNOME 和 KDE
桌面环境 特点 底层库
GNOME 简洁易用,Red Hat 默认 GTK+
KDE 功能丰富,可配置性强 Qt

7.6 API 与系统调用的关系

应用程序代码
    ↓ 调用
API(应用程序编程接口)
  ├── 如:C 标准库 `printf()`
  ├── 如:Win32 API `CreateWindow()`
  └── 如:Java API `FileInputStream.read()`
    ↓ 内部调用
系统调用(操作系统内核服务)

API 是提供给程序员的函数接口,系统调用是 API 底层真正去请求操作系统的机制。


第 8 章 死锁

8.1 什么是死锁?

定义: 多个进程互相等待对方占有的资源,导致所有相关进程都无法继续执行的状态。

通俗理解: 两个人在独木桥上相遇,你等他让,他等你让——结果谁都走不了。

经典例子:

进程 A 拿着资源 1,请求资源 2
进程 B 拿着资源 2,请求资源 1
→ A 等 B,B 等 A → 陷入死锁!

8.2 死锁的四个必要条件

四个条件必须同时满足才会发生死锁! 破坏任意一个,死锁就不会发生。

条件 名称 通俗解释
1️⃣ 互斥(Mutual Exclusion) 一个资源一次只能被一个进程使用
2️⃣ 占有并等待(Hold and Wait) 进程占有一个资源,同时等待其他资源
3️⃣ 不可剥夺(No Preemption) 资源只能由进程主动释放,系统不能强行拿走
4️⃣ 循环等待(Circular Wait) 存在一个循环链,每个进程都在等链中下一个进程的资源

麻将类比: 四个人打麻将准备胡牌,每人各缺一张特定的牌。

  • 互斥:每张牌在桌上只有一张
  • 占有并等待:每人手上有牌,还想要别人手里的牌
  • 不可剥夺:不能抢别人手上的牌
  • 循环等待:A 要 B 的、B 要 C 的、C 要 D 的、D 要 A 的
    → 死局!

8.3 资源分配图

图形化分析死锁的工具:

图形元素 含义
○(圆圈) 进程
□(方块) 资源(圆点表示资源实例数量)
← (进程→资源) 进程请求资源
← (资源→进程) 资源已分配给进程

判断规则:

  1. 图中没有环 → 没有死锁 ✅
  2. 图中有环,且每个资源只有一个实例 → 必然死锁 ❌
  3. 图中有环,但资源有多个实例 → 可能死锁,需要进一步分析

8.4 处理死锁的四种策略

┌──────────────────────────────────┐
│          死锁问题处理              │
├──────────────────────────────────┤
│ ① 死锁预防(严格预防,代价高)      │
│ ② 死锁避免(银行家算法,较灵活)    │
│ ③ 死锁检测与恢复(允许发生再处理)  │
│ ④ 鸵鸟策略(忽略死锁)            │
└──────────────────────────────────┘
① 死锁预防

破坏四个必要条件之一:

破坏条件 方法 代价
破坏互斥 用虚拟化技术(如打印机的 SPOOLing) 对不可共享资源不适用
破坏占有并等待 一次性申请所有资源 资源利用率低
破坏不可剥夺 系统可以强行收回资源 实现复杂,可能丢失工作
破坏循环等待 资源编号,按顺序申请 编号困难,资源利用率低
② 死锁避免(银行家算法)

创始人: Dijkstra(1965 年)

核心思想: 像一个谨慎的银行家,放贷前判断:如果放贷会导致资金链断裂(死锁),就拒绝。

数据结构:

结构 含义
Available[m] 每种资源当前可用的数量
Max[n][m] 每个进程对每种资源的最大需求
Allocation[n][m] 每个进程已分配的资源数量
Need[n][m] 每个进程还需要的资源数量(Need = Max - Allocation)

算法流程:

① 进程 Pi 请求资源 Request[i]
② 如果 Request[i] > Need[i] → 错误(超过声明需求)
③ 如果 Request[i] > Available → 暂时无法满足,等待
④ 系统"假装"分配资源:
   Available = Available - Request[i]
   Allocation[i] = Allocation[i] + Request[i]
   Need[i] = Need[i] - Request[i]
⑤ 执行"安全性检查"(判断是否处于安全状态)
⑥ 安全 → 真正分配;不安全 → 回滚,让进程等待

安全性检查:

① 设置 Work = Available, Finish[1..n] = false
② 找一个 Finish[i] = false 且 Need[i] ≤ Work 的进程
③ 如果找到 → Work = Work + Allocation[i], Finish[i] = true, 回到 ②
④ 如果所有 Finish[i] = true → 系统处于安全状态 ✅
   否则 → 不安全 ❌

安全状态: 存在一个进程执行序列,让所有进程都能完成。
不安全状态 ≠ 死锁,但不安全状态可能演变为死锁。

③ 死锁检测与恢复

允许死锁发生,但定期检测并恢复。

检测方法:

  • 用资源分配图分析是否存在循环等待
  • 定期运行检测算法

恢复方法:

  • 终止进程:终止所有死锁进程,或逐个终止直到死锁解除
  • 资源抢占:从部分进程收回资源给其他进程
    • 选择"受害进程"(代价最小)
    • 回滚到安全状态
④ 鸵鸟策略

“把头埋进沙子里,假装没看到问题。”

  • 大多数个人电脑操作系统(Windows、Linux)采用此策略
  • 死锁发生的概率远低于预防/避免的代价

8.5 经典同步问题

生产者-消费者问题

问题描述:

  • 生产者不断产生数据放到缓冲区
  • 消费者不断从缓冲区取出数据处理
  • 缓冲区满了生产者要等,缓冲区空了消费者要等

用信号量解决:

semaphore mutex = 1;   // 互斥访问缓冲区
semaphore empty = N;   // 空位数量
semaphore full = 0;    // 已填满的缓冲区数量

// 生产者
while(TRUE) {
    produce_item();
    P(empty);       // 空位减一,如果没有空位则等待
    P(mutex);       // 进入临界区
    put_item();
    V(mutex);       // 离开临界区
    V(full);        // 满位加一
}

// 消费者
while(TRUE) {
    P(full);        // 满位减一,如果没有则等待
    P(mutex);       // 进入临界区
    get_item();
    V(mutex);       // 离开临界区
    V(empty);       // 空位加一
    consume_item();
}

⚠️ 注意: PV 操作的顺序很重要!如果生产者先 P(mutex)P(empty),当缓冲区满时,生产者会拿着互斥锁等待空位——消费者无法进入临界区消费 → 死锁!


第 9 章 嵌入式操作系统

9.1 什么是嵌入式系统

通俗理解: 专门用于特定设备的"小电脑"——不是通用计算机,而是某个设备内部的"大脑"。

无处不在的嵌入式系统:

领域 例子
消费电子 智能手机、智能手表、智能电视
汽车 发动机控制系统、ABS 刹车系统、车载娱乐系统
家用电器 洗衣机、微波炉、智能冰箱
医疗设备 心脏起搏器、CT 扫描仪
工业控制 PLC、机器人控制器
网络设备 路由器、交换机、基站
军事/航空 导弹制导、飞行控制

9.2 嵌入式操作系统的特点

特点 说明
小型化 代码量小(几十KB到几MB),占用内存少
实时性 必须在规定的时限内响应外部事件
专用性 针对特定硬件和应用定制优化
可靠性 不能崩溃(特别是安全关键系统)
低功耗 电池供电,功耗必须严格控制
成本敏感 硬件成本必须低

9.3 实时操作系统(RTOS)

实时系统分类:

类型 特点 错过截止时间的后果 例子
硬实时 严格,绝对不能超时 灾难性后果 安全气囊、飞行控制
软实时 偶尔超时可以接受 性能下降 视频播放、在线游戏
RTOS 的核心功能
功能 说明
任务管理 多任务调度,优先级管理
中断管理 快速响应外部中断
时钟管理 精确计时,定时器管理
内存管理 快速、可预测的内存分配(通常不用 MMU)
I/O 管理 管理各种传感器和外设
同步与通信 信号量、消息队列、邮箱等
优先级反转(Priority Inversion)

问题: 高优先级任务被低优先级任务阻塞,因为低优先级任务占用了高优先级需要的共享资源。

优先级高 ─── 任务H(等待资源R)
优先级中 ─── 任务M(执行,抢占低优先级)
优先级低 ─── 任务L(持有资源R)

时间线:
1. 任务L 获得资源R,开始执行
2. 任务H 被唤醒,需要资源R,但 L 还持有 R → H 阻塞
3. 任务M 被唤醒,抢占 L(L 还未释放 R)→ M 执行
4. 任务H 虽然优先级最高,却要等到 M 和 L 都完成 → **优先级反转!**

解决方案:

  • 优先级继承:当低优先级任务持有高优先级需要的资源时,临时获得高优先级
  • 优先级天花板:给资源设置最高优先级,占有资源的任务继承该优先级
嵌入式系统中的中断处理

嵌入式系统对中断的响应时间要求极高。RTOS 通常做到:

  • 中断延迟:从硬件中断发生到第一条中断指令执行的延迟
  • 典型 RTOS 中断延迟:微秒级别

9.4 常见的嵌入式操作系统

系统 特点 应用领域
VxWorks 商业 RTOS,高可靠性 航空航天、工业控制
FreeRTOS 开源,轻量级 物联网、MCU
uC/OS 可裁剪,适合教育 学习、中小型系统
RT-Thread 国产,开源,功能丰富 物联网、智能设备
嵌入式 Linux 功能强大,但不是硬实时 路由器、智能设备
Android 基于 Linux 的移动系统 手机、平板
iOS Apple 移动系统 iPhone、iPad

9.5 华为鸿蒙操作系统(Harmony OS)

  • 2019 年发布
  • 面向"全场景"的分布式操作系统
  • 核心理念:“一次开发,多端部署”
  • 特点:
    1. 分布式架构(跨设备协同)
    2. 确定性时延引擎(硬实时能力)
    3. 弹性部署(按需裁剪)
    4. 统一 OS,适配不同设备(手机、平板、车机、IoT)

9.6 嵌入式系统的开发方式

  • 交叉编译:在 PC 上编译,在嵌入式设备上运行
  • JTAG/SWD 调试:通过调试接口连接开发板
  • 裸机开发:没有 OS,直接在硬件上运行
  • RTOS 开发:使用实时多任务系统

第 10 章 分布式系统和云计算

10.1 分布式系统概述

定义: 多台独立的计算机通过网络连接,协同工作,对外表现为"一台强大"的计算机。

就像很多蚂蚁一起搬食物,每只蚂蚁分担一部分重量,外人看起来就是"食物在移动"。

分布式系统的特点
特点 说明
资源共享 多台计算机共享硬件、软件、数据
并行性 多个任务在不同计算机上同时执行
透明性 用户感觉不到是多台计算机在协作
可扩展性 可以轻松增加更多计算机以提升性能
容错性 部分机器故障不影响整体服务
异构性 不同硬件、操作系统可以协同工作
分布式系统的挑战
  1. 通信延迟 — 网络传输比内存访问慢得多
  2. 时钟同步 — 不同计算机时钟不一致
  3. 一致性维护 — 多台计算机数据保持一致很困难
  4. 安全性 — 数据在网络传输中可能被窃取或篡改
  5. 故障处理 — 部分节点故障时的处理

10.2 分布式系统的关键技术

10.2.1 通信

远程过程调用(RPC):

  • 让程序像调用本地函数一样调用远程计算机的函数
  • 序列化/反序列化参数
  • 网络传输透明化

类比: 你打电话给朋友(远程调用),让他帮你查个资料(远程执行),他在那边查完告诉你结果(返回结果)。

10.2.2 时钟同步

问题: 每台计算机的时钟不同步。

Lamport 逻辑时钟(1978 年):

  • 不是同步时间,而是为事件排序
  • 每个事件分配一个"逻辑时间戳"
  • 如果 A → B(A 在 B 之前发生),则 LC(A) < LC(B)

向量时钟:

  • 解决 Lamport 时钟无法检测"并发事件"的缺陷
  • 每个节点维护一个向量,记录每个节点的最新时间
10.2.3 互斥

分布式互斥的三种方式:

方法 原理 特点
中央协调者 一个节点做"裁判" 简单,但单点故障
令牌环 令牌依次传递,有令牌才能进临界区 无饥饿,但通信量随节点数线性增长
分布式投票 需要多数节点同意 容错性好,但通信量大
10.2.4 一致性模型
模型 宽松程度 说明
严格一致性 最严格 任何写入立即可见
顺序一致性 严格 所有节点看到的操作顺序一致
最终一致性 宽松 只要不写入新值,最终所有副本一致
因果一致性 中等 有因果关系的操作按序可见

生活类比: 微博的点赞数——你可能看到 100 赞,我可能看到 102 赞,过一会儿都会更新到正确的数字,这就是"最终一致性"。

10.2.5 负载均衡

目标: 将工作负载均匀地分配到多台计算机上。

常见方法:

  1. 轮询(Round Robin) — 轮流分配请求
  2. 最少连接 — 分配给当前连接最少的服务器
  3. 哈希分配 — 基于请求的某些特征(如客户端 IP)分配
  4. 加权分配 — 性能好的服务器分更多请求

10.3 分布式操作系统 vs 网络操作系统

对比 网络操作系统 分布式操作系统
耦合度 松散 紧密
透明性 用户知道有不同计算机 用户感觉不到
资源管理 每台计算机自主管理 全局统一管理
例子 Windows 网络、NFS Amoeba、Plan 9

中间件(Middleware): 在分布式系统和应用程序之间提供标准接口的软件层,屏蔽底层异构性。

┌──────────────────────┐
│    应用程序           │
├──────────────────────┤
│    中间件(Middleware) │  ← 提供分布式服务抽象
├──────────────────────┤
│    操作系统            │
├──────────────────────┤
│    网络                │
└──────────────────────┘

10.4 多处理器系统

系统类型 架构 例子
多处理器系统 共享内存,多个 CPU SMP(对称多处理)
多计算机系统 不共享内存,消息传递 集群
网络系统 松散耦合,通过网络连接 局域网工作站
分布式系统 紧密/松散耦合,协同工作 云计算平台

10.5 云计算

通俗理解: 通过网络按需获取计算资源(服务器、存储、软件),就像用水用电一样方便。

生活类比:

  • 过去:每家自己打井取水(自己买服务器建机房)
  • 现在:用自来水公司(云服务商)的水,打开水龙头就有,按用量付费
云计算的三种服务模式
┌──────────────────────────────────┐
│           SaaS                   │
│  软件即服务(Software as a Service)│
│  直接用软件(如:Google Docs、企业微信)│
├──────────────────────────────────┤
│           PaaS                   │
│  平台即服务(Platform as a Service) │
│  在平台上开发部署(如:Google App Engine)│
├──────────────────────────────────┤
│           IaaS                   │
│  基础设施即服务(Infrastructure...)│
│  租用服务器/存储(如:AWS EC2)     │
└──────────────────────────────────┘

通俗化解释:

服务模式 自己管的 云服务商管的
IaaS 操作系统、应用、数据 硬件、网络、虚拟机管理
PaaS 应用、数据 硬件、操作系统、运行时
SaaS 数据(部分) 一切(硬件、平台、软件)
云的核心特性
特性 说明
按需自助 需要就开,用完就关
广泛网络访问 有网就能用
资源池化 多用户共享物理资源(逻辑隔离)
快速弹性 根据负载自动伸缩
可计量服务 用多少付多少
部署模型
部署方式 说明
公有云 第三方服务商提供,多租户
私有云 企业自建,仅供内部使用
混合云 公有云 + 私有云结合
社区云 多个组织共同使用

第 11 章 安全与保护机制

11.1 安全问题的来源

操作系统面临的安全威胁:

威胁类型 说明 例子
病毒 自我复制的恶意程序 蠕虫、文件感染病毒
木马 伪装成正常程序的恶意软件 伪装成游戏、破解工具
蠕虫 通过网络自我传播 Stuxnet 震网病毒
间谍软件 窃取用户信息 键盘记录器
后门 绕过正常认证的隐蔽入口 系统后门
拒绝服务(DDoS) 让系统无法正常服务 大量请求淹没服务器
社会工程学 欺骗用户泄露信息 钓鱼邮件

11.2 安全目标

CIA 三要素:

┌─────────────────┐
│ 机密性(C)      │ ← 信息只能被授权者访问
├─────────────────┤
│ 完整性(I)      │ ← 信息不被非法篡改
├─────────────────┤
│ 可用性(A)      │ ← 系统能正常提供服务
└─────────────────┘

其他重要目标:

  • 认证(Authentication) — 验证用户身份真伪
  • 授权(Authorization) — 确定用户能做什么
  • 审计(Audit) — 记录操作日志,事后追责
  • 不可否认性(Non-repudiation) — 用户不能否认自己的操作

11.3 威胁与攻击

攻击类型 机理 防范
缓冲区溢出 输入数据超过了缓冲区的边界 边界检查、ASLR
SQL 注入 在输入中嵌入 SQL 代码 参数化查询
跨站脚本(XSS) 在网页中注入恶意脚本 输入验证、转义
中间人攻击 拦截通信双方的数据 加密传输(HTTPS)
权限提升 从普通用户获取管理员权限 最小特权原则

11.4 访问控制

11.4.1 最小特权原则

Principle of Least Privilege

每个用户/程序只拥有完成其任务所需的最小权限

举例:

  • 前台只需要"查看订单"权限,不需要"删除订单"权限
  • 普通用户不需要系统管理权限
11.4.2 访问控制矩阵
          文件A      文件B      文件C      打印机
用户1      读         读/写        -         使用
用户2      读/写       -          读          -
用户3       -         读          写/执行     使用

实现方式:

方式 方向 存储方式 优点 缺点
ACL(访问控制列表) 面向文件 每个文件记录访问者列表 容易查看文件权限 删除用户麻烦
能力列表 面向用户 每个用户记录可访问的资源 容易查看用户权限 撤销权限麻烦
11.4.3 UNIX 权限控制

UNIX 中每个文件有三组权限:

  rwx   r-x   r--
  ─┼─   ─┼─   ─┼─
   │     │     └── 其他人权限(other)
   │     └──────── 同组权限(group)
   └────────────── 所有者权限(owner)

权限位含义:

  • r(4)= 读
  • w(2)= 写
  • x(1)= 执行

例子: rwxr-xr--

  • 所有者:读+写+执行
  • 同组用户:读+执行
  • 其他用户:只读
11.4.4 访问控制列表(ACL)

ACL(Access Control List) — 为每个文件列出哪些用户可以访问以及权限。

文件 F 的 ACL:
┌──────────┬───────┐
│ 用户 Alice │ read  │
│ 用户 Bob   │ write │
│ 组 staff  │ read  │
│ 其他人     │ none  │
└──────────┴───────┘
11.4.5 能力列表(Capability List)

与 ACL 相反: 不是"文件→谁可以访问",而是"用户→可以访问什么"。

就像你的钥匙扣上有不同的钥匙(能力),每把钥匙可以开特定的门。有了钥匙就能开门,没钥匙就不能。

11.5 可信系统

TCB(Trusted Computing Base,可信计算基) — 系统安全的基础组件集合。

TCB 包含:

  • 硬件(CPU、内存管理单元)
  • 操作系统内核的安全部分
  • 安全相关的系统调用
  • 认证模块

11.6 安全评估标准

TCSEC(美国国防部可信计算机系统评估标准,“橙皮书”)

级别 名称 描述
D 最低保护 无安全措施
C1 自主安全保护 基本的用户认证、文件权限
C2 受控访问保护 更细粒度访问控制、审计日志
B1 标签安全保护 给数据和用户加安全标签
B2 结构化保护 形式化安全模型
B3 安全域 高可靠性、最小权限
A1 验证设计 形式化验证安全

UNIX 系统通常达到 C2 级别。

11.7 加密与认证

加密(Encryption): 将数据转换成只有授权方才能理解的形式。

对称加密:

  • 加密和解密用同一个密钥
  • 算法:DES、AES
  • 优点:速度快
  • 缺点:密钥分发困难

非对称加密:

  • 使用公钥和私钥
  • 算法:RSA、ECC
  • 优点:密钥分发方便
  • 缺点:速度慢

数字签名: 用私钥签名,用公钥验证——确保信息完整性和来源真实性。

认证方式

方式 安全级别 例子
密码认证 用户名+密码
双因素认证 密码+手机验证码
生物特征 指纹、人脸、虹膜

11.8 保护机制

用户态与核心态:

  • 用户态 — 受限运行。应用程序运行在用户态
  • 核心态 — 可执行特权指令。操作系统内核运行在核心态

CPU 的保护环(Ring 0 ~ Ring 3):

Ring 0 ── 操作系统内核(最可信)    ← 所有权限
Ring 1 ── 设备驱动程序
Ring 2 ── 系统服务
Ring 3 ── 应用程序(最不可信)      ← 受限权限

🧠 学习路线建议(小白友好版)

第1章:操作系统引论
  └── 建立整体概念

第2章:进程和线程
  └── 核心概念:程序怎么运行

第8章:死锁
  └── 理解资源竞争问题

第4章:存储管理
  └── 核心概念:内存怎么管理

第5章:文件系统
  └── 核心概念:文件怎么存储

第6章:输入输出管理
  └── 核心概念:设备怎么控制

第3章:调度
  └── 深入:CPU 怎么分配

第7章:用户接口服务
  └── 实操:系统调用、Shell

第11章:安全与保护
  └── 扩展:怎么保证安全

第9章:嵌入式系统
  └── 扩展:小设备上的 OS

第10章:分布式与云计算
  └── 扩展:多台计算机协同

🔑 核心概念速查表

概念 一句话概括
操作系统 管理硬件和软件资源的"大管家"
进程 正在执行的程序(有独立内存空间)
线程 进程内的"子任务"(共享内存空间)
PCB 进程的"身份证"
调度 决定谁用 CPU、用多久
虚拟内存 让程序以为有超大内存(实际部分在硬盘)
分页 把内存分成 4KB 小格子管理
缺页中断 要访问的页不在内存中
文件系统 硬盘上文件的组织管理方式
i-node 文件的"ID 卡"(UNIX)
中断 设备通知 CPU 的方式
DMA 设备直接和内存交换数据,不经过 CPU
系统调用 程序请求操作系统服务
Shell 命令行解释器(人机交互)
死锁 进程互相等待,谁都动不了
银行家算法 避免死锁的"放贷"判断方法
嵌入式系统 专用设备中的"小系统"
分布式系统 多台计算机协同工作
云计算 按需租用计算资源
ACL 文件的"门禁名单"(谁可以访问)
最小特权 只给完成任务所需的最小权限

📝 本笔记基于操作系统教材 11 章内容整理,补充了实际案例和通俗解释。
欢迎在学习过程中随时补充笔记、画思维导图,把知识真正内化!

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐