操作系统 知识点大全【超详细!!!】

目录

第一章 操作系统概述

1.1 操作系统的基本概念

1.1.1 操作系统的定义

1.1.2 操作系统的特征

1.2 操作系统的发展历程

1.2.1 手工操作阶段(1940-1950年代)

1.2.2 批处理系统(1950-1960年代)

1.2.3 分时系统(1960年代)

1.2.4 现代操作系统(1980年代至今)

1.3 操作系统的功能组成

1.3.1 处理器管理

1.3.2 存储器管理

1.3.3 设备管理

1.3.4 文件管理

1.4 主流操作系统类型

1.4.1 批处理操作系统

1.4.2 分时操作系统

1.4.3 实时操作系统

1.4.4 嵌入式操作系统

1.5 操作系统体系结构

1.5.1 单体结构

1.5.2 层次结构

1.5.3 微内核结构

1.5.4 外核结构

1.6 现代操作系统发展趋势

1.6.1 多核与并行计算

1.6.2 云计算与虚拟化

1.6.3 安全与可信计算

1.6.4 物联网与边缘计算

第二章 操作系统运行机制

2.1 操作系统的运行架构

2.1.1 双模式运行机制

2.1.2 状态切换机制

2.2 中断处理机制

2.2.1 中断分类

2.2.2 中断处理流程

2.3 系统调用实现

2.3.1 系统调用与库函数对比

2.3.2 系统调用执行过程

2.4 操作系统内核结构

2.4.1 大内核(宏内核)架构

2.4.2 微内核架构

2.5 系统引导流程

2.5.1 启动阶段

2.5.2 关键组件

第三章 进程管理

3.1 进程的基本概念

3.1.1 进程的定义与特征

3.1.2 进程控制块(PCB)

3.2 进程的状态与转换

3.2.1 五状态模型

3.2.2 状态转换图

3.3 进程控制

3.3.1 进程创建

3.3.2 进程终止

3.4 进程同步

3.4.1 临界区问题

3.4.2 信号量机制

3.5 经典同步问题

3.5.1 生产者-消费者问题

3.5.2 读者-写者问题

3.6 进程通信

3.6.1 共享内存

3.6.2 消息传递

3.7 线程概念

3.7.1 线程与进程对比

3.7.2 线程实现模型

第四章 处理机调度与死锁

4.1 处理机调度层次

4.1.1 三级调度体系

4.2 调度算法

4.2.1 经典调度算法对比

4.2.2 调度性能指标

4.3 死锁原理

4.3.1 死锁定义与条件

4.3.2 死锁处理策略

4.4 死锁检测与恢复

4.4.1 资源分配图

4.4.2 恢复方法

4.5 综合案例分析

4.5.1 调度算法应用题

4.5.2 死锁避免题

第五章 存储器管理

5.1 存储器管理基础

5.1.1 存储体系层次

5.1.2 地址绑定时机

5.2 连续内存分配

5.2.1 分配策略对比

5.2.2 碎片处理

5.3 分页存储管理

5.3.1 基本分页机制

5.3.2 快表(TLB)优化

5.4 分段存储管理

5.4.1 分段vs分页

5.4.2 段表结构

5.5 虚拟内存技术

5.5.1 请求分页机制

5.5.2 页面置换算法

5.6 内存映射文件

5.6.1 传统文件访问vs内存映射

5.6.2 共享内存实现

5.7 存储保护机制

5.7.1 硬件支持

5.7.2 典型保护违规

第六章 文件管理

6.1 文件系统基础

6.1.1 文件概念与属性

6.1.2 文件类型

6.2 文件逻辑结构

6.2.1 无结构文件

6.2.2 有结构文件

(1) 顺序文件

(2) 索引文件

6.3 文件物理结构

6.3.1 连续分配

6.3.2 链接分配

(1) 隐式链接

(2) 显式链接

6.3.3 索引分配

6.4 目录管理

6.4.1 目录结构

(1) 单级目录

(2) 树形目录

6.4.2 目录操作

6.5 文件存储空间管理

6.5.1 空闲空间管理

(1) 空闲表法

(2) 位示图法

6.5.2 成组链接法(UNIX方案)

6.6 文件共享与保护

6.6.1 共享方式

(1) 硬链接

(2) 符号链接

6.6.2 访问控制

(1) 访问控制表(ACL)权限模型

(2) 文件保护矩阵

6.7 文件系统性能

6.7.1 磁盘缓存

6.7.2 磁盘调度

对比总结(基于本题)

第七章 设备管理

7.1 I/O系统概述

7.1.1 设备分类

按传输速率分类:

按信息组织方式分类:

7.1.2 设备控制器功能

7.2 I/O控制方式

7.2.1 四种控制方式对比

7.2.2 DMA工作流程

7.3 缓冲技术

7.3.1 缓冲类型

单缓冲

双缓冲(乒乓缓冲)

循环缓冲

7.3.2 缓冲池管理

7.4 设备分配与回收

7.4.1 设备分配策略

静态分配

动态分配

7.4.2 设备分配过程

7.5 磁盘管理

7.5.1 磁盘调度算法(第六章讲过)

7.5.2 磁盘性能计算

7.6 设备驱动程序

7.6.1 驱动结构

7.6.2 驱动加载流程

7.7 关键问题解决方案

7.7.1 中断处理优化

7.7.2 设备无关性实现


第一章 操作系统概述

1.1 操作系统的基本概念

操作系统(Operating System,OS)是计算机系统中最为核心的系统软件,它是硬件与应用程序之间的桥梁,负责管理和协调计算机系统的各种资源。从用户角度看,操作系统是一个控制计算机的程序;从系统角度看,它则是资源管理器和扩展机器。

1.1.1 操作系统的定义

操作系统可以被定义为:

  • 资源管理者:有效管理计算机系统的硬件和软件资源

  • 服务提供者:为用户和应用程序提供便捷的使用接口

  • 系统控制者:协调和控制计算机系统中各个部件的运行

1.1.2 操作系统的特征

现代操作系统通常具备以下基本特征:

  1. 并发性(Concurrency)

    • 指系统能够处理多个同时发生的活动

    • 通过进程和线程机制实现

    • 示例:用户可以边听音乐边编辑文档

  2. 共享性(Sharing)

    • 系统资源可供多个并发执行的程序共同使用

    • 包括两种共享方式:

      • 互斥共享(如打印机)

      • 同时访问(如磁盘文件)

  3. 虚拟性(Virtualization)

    • 将物理实体映射为多个逻辑对应物

    • 典型实现:

      • CPU虚拟化(分时复用)

      • 内存虚拟化(虚拟地址空间)

  4. 异步性(Asynchronism)

    • 程序的执行以不可预知的速度推进

    • 操作系统必须保证在任意环境下都能获得正确结果

1.2 操作系统的发展历程

1.2.1 手工操作阶段(1940-1950年代)

  • 特点:

    • 程序员直接操作机器

    • 串行处理作业

    • 资源利用率极低

  • 典型问题:

    • CPU等待手工操作

    • 大量人工干预

1.2.2 批处理系统(1950-1960年代)

  • 简单批处理

    • 引入监控程序(Monitor)

    • 作业自动连续处理

    • 减少人工干预

  • 多道批处理

    • 关键技术突破:

      • 中断技术

      • 通道技术

    • 主要特征:

      • 内存中同时存放多道程序

      • CPU与I/O设备并行工作

1.2.3 分时系统(1960年代)

  • 革命性创新:

    • 时间片轮转机制

    • 交互式操作界面

  • 典型系统:

    • CTSS(兼容分时系统)

    • MULTICS

    • UNIX前身

1.2.4 现代操作系统(1980年代至今)

  • 主要发展方向:

    • 个人计算机操作系统(Windows、macOS)

    • 分布式操作系统

    • 实时操作系统

    • 嵌入式操作系统

1.3 操作系统的功能组成

1.3.1 处理器管理

  • 核心功能:

    • 进程控制(创建/撤销/阻塞/唤醒)

    • 进程同步(互斥/同步机制)

    • 进程通信(共享内存/消息传递)

    • 进程调度(作业/进程/线程调度)

1.3.2 存储器管理

  • 主要任务:

    • 内存分配与回收

    • 地址转换(逻辑→物理)

    • 内存保护(隔离不同进程)

    • 虚拟内存管理

1.3.3 设备管理

  • 关键功能:

    • 设备分配

    • 设备驱动

    • 缓冲管理

    • 虚拟设备(SPOOLing技术)

1.3.4 文件管理

  • 核心职责:

    • 文件存储空间管理

    • 目录管理

    • 文件读写控制

    • 文件保护机制

1.4 主流操作系统类型

1.4.1 批处理操作系统

  • 典型特征:

    • 作业成批处理

    • 无用户交互

    • 高吞吐量

  • 现代应用:

    • 科学计算任务

    • 后台数据处理

1.4.2 分时操作系统

  • 主要特点:

    • 多用户同时访问

    • 交互式响应

    • 公平的时间分配

  • 代表系统:

    • UNIX/Linux

    • OpenVMS

1.4.3 实时操作系统

  • 关键指标:

    • 严格的时间约束

    • 高可靠性

    • 可预测性

  • 分类:

    • 硬实时(工业控制)

    • 软实时(多媒体系统)

1.4.4 嵌入式操作系统

  • 特殊要求:

    • 资源受限环境

    • 低功耗设计

    • 实时性要求

  • 典型代表:

    • VxWorks

    • FreeRTOS

    • 华为LiteOS

1.5 操作系统体系结构

1.5.1 单体结构

  • 特点:

    • 所有功能模块在内核态运行

    • 模块间直接调用

  • 优点:

    • 高性能

    • 简单直接

  • 缺点:

    • 可维护性差

    • 可靠性风险

1.5.2 层次结构

  • 典型分层(自底向上):

    1. 硬件抽象层

    2. 内存管理

    3. 进程管理

    4. I/O管理

    5. 用户接口

1.5.3 微内核结构

  • 设计理念:

    • 最小化内核功能

    • 多数服务运行在用户态

  • 优势:

    • 高可靠性

    • 易扩展性

  • 代表系统:

    • Mach内核

    • Windows NT(部分采用)

1.5.4 外核结构

  • 创新思想:

    • 将资源保护与抽象分离

    • 应用程序直接管理硬件资源

    • 内核仅负责安全隔离

1.6 现代操作系统发展趋势

1.6.1 多核与并行计算

  • 挑战:

    • 并行编程模型

    • 资源竞争管理

    • 能耗控制

1.6.2 云计算与虚拟化

  • 关键技术:

    • 容器技术(Docker)

    • 虚拟机监控器(Hypervisor)

    • 弹性资源分配

1.6.3 安全与可信计算

  • 发展方向:

    • 可信执行环境(TEE)

    • 硬件级安全(SGX)

    • 零信任架构

1.6.4 物联网与边缘计算

  • 特殊需求:

    • 轻量级内核

    • 实时响应

    • 分布式协同

本章重点概念:操作系统定义、四大特征(并发/共享/虚拟/异步)、五大管理功能(处理机/存储/设备/文件/用户接口)、四大类型(批处理/分时/实时/嵌入式)

第二章 操作系统运行机制

2.1 操作系统的运行架构

2.1.1 双模式运行机制

  • 内核态(Kernel Mode)

    • PSW寄存器状态位为1

    • 可执行特权指令

    • 访问所有硬件资源

    • 运行操作系统内核程序

  • 用户态(User Mode)

    • PSW寄存器状态位为0

    • 仅能执行非特权指令

    • 受限的资源访问

    • 运行应用程序

2.1.2 状态切换机制

  • 用户态→内核态

    • 通过中断自动触发(硬件完成PSW修改)

    • 典型场景:

      • 系统调用(执行陷入指令)

      • 硬件中断(时钟/I/O)

      • 程序异常(如除零错误)

  • 内核态→用户态

    • 通过特权指令显式设置PSW

    • 在中断/系统调用处理完毕后执行

2.2 中断处理机制

2.2.1 中断分类

中断类型触发源典型场景处理特点
内中断CPU内部①执行特权指令(用户态)同步发生
(异常)②除零错误等异常不可屏蔽
③陷入指令(系统调用)
外中断外部设备①时钟中断(时间片到期)异步发生
②I/O中断(设备操作完成)可屏蔽/非屏蔽

2.2.2 中断处理流程

  1. 中断触发:硬件检测到中断信号

  2. 状态保存:自动压栈保存PSW和PC值

  3. 模式切换:硬件将PSW置为内核态(1)

  4. 查向量表:根据中断类型号定位处理程序

  5. 执行处理:运行对应的中断服务例程

  6. 恢复现场:恢复PSW和PC,返回用户态

关键数据结构
中断向量表——存储各中断处理程序入口地址的数组,下标对应中断类型号

2.3 系统调用实现

2.3.1 系统调用与库函数对比

特性系统调用库函数
执行环境必须在内核态执行通常在用户态执行
实现位置操作系统内核语言运行时库
功能范围资源相关操作通用功能
调用开销高(需模式切换)低(无状态转换)
示例fork()open()abs()strcpy()

2.3.2 系统调用执行过程

    应用程序->>+内核: 1. 传递系统调用参数
    应用程序->>+内核: 2. 执行陷入指令(如int 0x80)
    内核-->>-硬件: 3. 触发内中断(自动完成)
    硬件->>+内核: 4. 保存现场并切换至内核态
    内核->>内核: 5. 查系统调用表定位处理程序
    内核->>内核: 6. 执行具体服务例程
    内核-->>-硬件: 7. 执行特权指令恢复用户态
    硬件-->>-应用程序: 8. 返回结果并继续执行

2.4 操作系统内核结构

2.4.1 大内核(宏内核)架构

  • 特点

    • 所有核心功能(进程管理、内存管理等)都在内核空间运行

    • 模块间通过函数调用直接通信

  • 优势

    • 高性能(无模式切换开销)

    • 功能集成度高

  • 缺点

    • 可靠性风险(任一模块错误导致全系统崩溃)

    • 可维护性差

  • 典型代表

    • Linux内核

    • Windows NT内核(部分模块化)

2.4.2 微内核架构

  • 特点

    • 仅最基本功能(IPC、地址空间)在内核

    • 其他服务(文件系统、驱动)运行在用户态

  • 优势

    • 高可靠性(故障隔离)

    • 易于扩展

  • 缺点

    • 性能开销(频繁模式切换)

  • 典型代表

    • Mach内核(macOS基础)

    • QNX实时系统

2.5 系统引导流程

2.5.1 启动阶段

  1. BIOS/UEFI阶段

    • 硬件自检(POST)

    • 从固定地址(0xFFFF0)执行ROM引导程序

    • 读取主引导记录(MBR/GPT)

  2. 引导加载阶段

    • 加载bootloader(如GRUB)

    • 扫描活动分区

    • 读取分区引导记录

  3. 内核初始化

    • 加载内核映像到内存

    • 初始化关键数据结构(页表、中断向量表等)

    • 启动init进程(PID=1)

2.5.2 关键组件

  • 主引导记录(MBR)

    • 位于磁盘第一个扇区(512字节)

    • 包含:引导代码(446B)+分区表(64B)+魔数(0x55AA)

  • init进程

    • 所有用户进程的祖先

    • 负责启动系统服务(如getty、网络守护进程)

第三章 进程管理

3.1 进程的基本概念

3.1.1 进程的定义与特征

进程是操作系统中最基本的执行单元,经典定义包括:

  • 执行中的程序:程序的一次动态执行过程

  • 资源分配单位:系统进行CPU调度和资源分配的基本实体

  • 具有独立功能的程序:在某个数据集合上的一次运行活动

进程的五大特征

  1. 动态性:具有生命周期(创建→运行→终止)

  2. 并发性:多个进程可同时存在于内存中

  3. 独立性:各进程拥有独立的地址空间和系统资源

  4. 异步性:进程以不可预知的速度推进

  5. 结构性:由程序段、数据段和进程控制块(PCB)组成

3.1.2 进程控制块(PCB)

PCB是操作系统管理进程的核心数据结构,包含:

struct PCB {
    int pid;                // 进程标识符
    int state;              // 进程状态(就绪/运行/阻塞等)
    int priority;           // 优先级
    struct registers regs;  // 寄存器保存区
    void *mem_base;         // 内存分配基址
    struct list_head list;  // 进程队列指针
    // ...其他控制信息
};

PCB主要功能

  • 唯一标识进程(通过PID)

  • 保存进程运行现场(寄存器值)

  • 记录资源分配情况

  • 实现进程调度(状态/优先级)

3.2 进程的状态与转换

3.2.1 五状态模型

状态描述转换条件
新建态进程正在被创建分配PCB→就绪态
就绪态已获得除CPU外的所有资源被调度程序选中→运行态
运行态正在CPU上执行时间片用完→就绪态
等待事件→阻塞态
正常结束→终止态
阻塞态因等待某事件(如I/O完成)而暂停执行等待的事件发生→就绪态
终止态进程执行完毕或被强制终止资源回收,PCB撤销

3.2.2 状态转换图

3.3 进程控制

3.3.1 进程创建

创建事件

  • 用户登录(终端连接)

  • 作业调度(批处理系统)

  • 用户请求(shell命令或GUI操作)

  • 服务调用(系统进程创建)

创建过程(UNIX fork()示例):

  1. 分配唯一PID

  2. 复制父进程PCB

  3. 分配资源(内存、文件等)

  4. 初始化子进程特定字段

  5. 插入就绪队列

3.3.2 进程终止

终止方式

  • 正常结束(exit()系统调用)

  • 异常结束(段错误、除零等)

  • 外界干预(kill信号)

终止处理

  1. 关闭所有打开文件

  2. 释放内存资源

  3. 通知父进程(通过SIGCHLD)

  4. 撤销PCB

3.4 进程同步

3.4.1 临界区问题

临界资源:一次仅允许一个进程使用的资源(如打印机)

临界区:访问临界资源的代码段

解决方案要求

  1. 互斥进入(Mutual Exclusion)

  2. 有空让进(Progress)

  3. 有限等待(Bounded Waiting)

3.4.2 信号量机制

整型信号量(存在忙等问题):

void wait(int *S) {
    while (*S <= 0);  // 忙等
    (*S)--;
}

void signal(int *S) {
    (*S)++;
}

记录型信号量(标准实现):

typedef struct {
    int value;
    struct process *queue;
} semaphore;

void P(semaphore *S) {
    S->value--;
    if (S->value < 0) {
        block(S->queue);  // 自我阻塞
    }
}

void V(semaphore *S) {
    S->value++;
    if (S->value <= 0) {
        wakeup(S->queue);  // 唤醒等待进程
    }
}

3.5 经典同步问题

3.5.1 生产者-消费者问题

问题描述

  • 生产者向缓冲区放入产品

  • 消费者从缓冲区取出产品

  • 缓冲区大小为N(有限资源)

信号量解法

semaphore mutex = 1;    // 缓冲区互斥
semaphore empty = N;    // 空闲缓冲区数
semaphore full = 0;     // 已用缓冲区数

void producer() {
    while (1) {
        item = produce_item();
        P(&empty);
        P(&mutex);
        insert_item(item);
        V(&mutex);
        V(&full);
    }
}

void consumer() {
    while (1) {
        P(&full);
        P(&mutex);
        item = remove_item();
        V(&mutex);
        V(&empty);
        consume_item(item);
    }
}

3.5.2 读者-写者问题

问题变种

  • 读者优先(可能导致写者饥饿)

  • 写者优先(增加读写公平性)

读者优先解法

semaphore rw_mutex = 1;  // 读写互斥
semaphore mutex = 1;     // read_count保护
int read_count = 0;

void reader() {
    while (1) {
        P(&mutex);
        read_count++;
        if (read_count == 1) P(&rw_mutex);
        V(&mutex);
        
        // 执行读操作
        
        P(&mutex);
        read_count--;
        if (read_count == 0) V(&rw_mutex);
        V(&mutex);
    }
}

void writer() {
    while (1) {
        P(&rw_mutex);
        // 执行写操作
        V(&rw_mutex);
    }
}

3.6 进程通信

3.6.1 共享内存

实现步骤

  1. 创建共享内存区(shmget)

  2. 附加到进程地址空间(shmat)

  3. 直接读写内存访问

  4. 分离共享内存(shmdt)

特点

  • 最快的IPC方式

  • 需要自行处理同步问题

3.6.2 消息传递

直接通信

send(PID, message);  // 指定目标进程
receive(PID, &message);

间接通信(通过信箱):

send(mailbox, message);
receive(mailbox, &message);

3.7 线程概念

3.7.1 线程与进程对比

特性进程线程
资源拥有独立地址空间和资源共享进程资源
切换开销大(需保存完整上下文)小(仅保存寄存器)
创建速度
通信方式IPC(管道、消息队列等)直接读写共享变量

3.7.2 线程实现模型

用户级线程(ULT)

  • 优点:切换无需内核介入

  • 缺点:一个线程阻塞导致整个进程阻塞

内核级线程(KLT)

  • 优点:内核感知线程,可并行执行

  • 缺点:切换需要陷入内核

混合模型

  • 多对多映射(n用户线程→m内核线程)

  • 兼顾灵活性与效率

第四章 处理机调度与死锁

4.1 处理机调度层次

4.1.1 三级调度体系

调度层次触发频率操作对象主要功能状态影响
高级调度 (作业调度)分钟级作业从外存后备队列选择作业调入内存并创建进程无→创建态→就绪态
中级调度 (内存调度)秒级进程决定哪些挂起进程重新调入内存(对应七状态模型中的"挂起态"处理)挂起态↔就绪态/阻塞态
低级调度 (进程调度)毫秒级进程/线程从就绪队列选择进程分配CPU,是操作系统最基本的功能就绪态↔运行态

关键细节

  • 中级调度是平衡系统负载的重要手段,当内存紧张时将进程数据调至外存(挂起),空闲时再调回

  • 七状态模型在五状态基础上增加"就绪挂起"和"阻塞挂起"状态(PDF第22页图示)

4.2 调度算法

4.2.1 经典调度算法对比

算法规则描述可抢占性优点缺点是否导致饥饿
FCFS按到达顺序服务不可抢占实现简单对短作业不利
SJF选择预估运行时间最短的作业可抢占平均等待时间最短长作业可能饥饿
HRRN选择响应比最高的作业
(响应比=1+等待时间/预估运行时间)
不可抢占兼顾长短作业需要预估运行时间
RR按时间片轮转抢占式公平,响应快频繁切换开销大
优先级选择优先级最高的进程可配置区分任务紧急程度低优先级进程可能饥饿
多级反馈队列设置多级队列,时间片递增抢占式综合性能最优参数配置复杂可能

重点算法示例

  1. 时间片轮转

    • 时间片=2时进程执行顺序:P1→P2→P1→P3→P2→P4→P4

    • 时间片=5时退化为FCFS

  2. 多级反馈队列

    # 三级队列配置示例
    queues = [
        {'time_slice': 2, 'priority': 'HIGH'},   # 队列1
        {'time_slice': 4, 'priority': 'MEDIUM'}, # 队列2
        {'time_slice': 'FCFS', 'priority': 'LOW'} # 队列3
    ]

4.2.2 调度性能指标

指标计算公式意义说明
CPU利用率CPU有效工作时间 / 总时间衡量CPU忙碌程度
系统吞吐量完成作业数 / 总时间单位时间内完成的工作量
周转时间作业完成时间 - 提交时间作业从提交到完成的总时间
带权周转时间周转时间 / 实际运行时间反映作业的相对等待时间
响应时间首次响应时间 - 提交时间交互式系统的关键指标

4.3 死锁原理

4.3.1 死锁定义与条件

死锁定义:多个进程因竞争资源而造成的一种互相等待的现象,若无外力作用,这些进程都将无法向前推进。

四个必要条件

  1. 互斥条件:资源一次只能由一个进程占用

  2. 请求与保持:进程持有资源的同时请求新资源

  3. 不可抢占:已分配资源不能被强制剥夺

  4. 循环等待:存在进程-资源的循环等待链

4.3.2 死锁处理策略

策略实现方法优点缺点
预防破坏四个必要条件中的至少一个彻底避免死锁资源利用率降低
避免银行家算法:仅当系统处于安全状态时才分配资源允许并发最大化需预知最大资源需求
检测定期构建资源分配图,检测环路不影响正常执行检测开销大
解除1. 资源剥夺
2. 进程回退
3. 进程终止
快速恢复系统可能造成工作丢失

银行家算法示例

# 系统资源总量
Available = [3, 3, 2]

# 各进程最大需求
Max = [
    [7, 5, 3],  # P0
    [3, 2, 2],  # P1
    [9, 0, 2],  # P2
    [2, 2, 2],  # P3
    [4, 3, 3]   # P4
]

# 已分配资源
Allocation = [
    [0, 1, 0],  # P0
    [2, 0, 0],  # P1
    [3, 0, 2],  # P2
    [2, 1, 1],  # P3
    [0, 0, 2]   # P4
]

# 计算Need矩阵
Need = [[Max[i][j] - Allocation[i][j] for j in range(3)] for i in range(5)]

4.4 死锁检测与恢复

4.4.1 资源分配图

图元素

  • 圆形节点:表示进程

  • 方形节点:表示资源类(其中的点表示实例)

  • 请求边:P → R(进程请求资源)

  • 分配边:R → P(资源已分配给进程)

检测算法

  1. 找出非阻塞进程(其请求可被满足)

  2. 模拟资源回收,移除此进程的所有边

  3. 重复上述步骤,若最终图中存在边则检测到死锁

4.4.2 恢复方法

进程终止策略

  1. 优先级最低优先:牺牲对系统影响最小的进程

  2. 进度最慢优先:终止已完成工作量最少的进程

  3. 资源消耗最多优先:释放最多资源的进程

  4. 级联终止:终止整个进程组

资源剥夺策略

  • 选择被抢占进程的标准:

    1. 已持有资源数量

    2. 剩余执行时间预估

    3. 优先级因素

4.5 综合案例分析

4.5.1 调度算法应用题

给定进程信息:

进程到达时间运行时间
P107
P224
P341
P454

SJF调度结果

时间轴:0-7(P1), 7-8(P3), 8-12(P2), 12-16(P4)
平均周转时间 = [(7-0)+(12-2)+(8-4)+(16-5)]/4 = 8.5

4.5.2 死锁避免题

假设系统当前资源分配如下:

进程AllocationNeed
P00 1 07 4 3
P12 0 01 2 2

Available = [3 3 2]

安全序列验证

  1. 检查Need <= Available的进程(P1满足)

  2. 假设P1执行完成,释放资源:Available = [5 3 2]

  3. 接着可选择P0执行,最终得到安全序列<P1, P0>

第五章 存储器管理

5.1 存储器管理基础

5.1.1 存储体系层次

CPU寄存器->高速缓存->主存储器->磁盘缓存->固定磁盘->可移动存储

关键特性对比

存储层级访问时间容量成本/位管理主体
寄存器1ns<1KB最高编译器
高速缓存2-10ns1-8MB硬件
主存10-100ns4-256GB操作系统
磁盘5-20ms1-100TB操作系统/应用

5.1.2 地址绑定时机

  1. 编译时绑定:(绝对装入)

    • 生成绝对代码

    • 必须装入指定内存位置

    • 早期DOS程序常用方式

  2. 加载时绑定:(可重定位装入)

    • 生成可重定位代码

    • 装入时确定实际地址

    • 需硬件重定位寄存器支持

  3. 运行时绑定:(动态重定位装入)

    • 执行期间可改变物理地址

    • 需要MMU(内存管理单元)硬件

    • 现代操作系统通用方案

5.2 连续内存分配

5.2.1 分配策略对比

策略分区方式碎片问题实现复杂度适用场景
单一连续整个用户区独占内部碎片简单单道批处理系统
固定分区预先划分等/不等大小分区内部碎片中等早期多道系统
动态分区按需划分外部碎片复杂通用系统

动态分区分配算法

首次适应算法:每次都从低地址开始查找,找到第一个能满足大小的空闲分区

实现:空闲分区以地址递增的次序链接,顺序查找空闲分区链分区表

 

循环首次适应算法:不从链首开始查找,而是从上次找到的空闲分区的下一个空闲分区开始查找

实现:空闲分区以地址递增的次序链接(循环链表),顺序查找空闲分区链分区表

 

最佳适应算法:尽可能留下大片的空闲区,优先使用更小的空闲区

实现:空闲分区以容量递增次序链接顺序查找空闲分区链分区表。分配后要重新连接分区链,保持容量递增

 

最坏适应算法:优先使用最大的连续空闲区

实现:空闲分区以容量递减次序链接,顺序查找空闲分区链分区表。分配后要重新连接分区链,保持容量递减

5.2.2 碎片处理

  • 内部碎片:已分配分区中未被利用的部分(固定分区必然存在)

  • 外部碎片:分散的小空闲区无法满足需求(动态分区产生)

  • 解决方案

    1. 紧凑技术(Compaction):动态重定位运行中的程序

    2. 分页技术:彻底消除外部碎片

5.3 分页存储管理

5.3.1 基本分页机制

地址转换流程

逻辑地址 → 页号(p) + 页内偏移(d)
            ↓
        查页表(PMT)
            ↓
物理地址 → 页框号(f) + 页内偏移(d)

页表项结构

位域作用
0-11页框号(4KB页对应12位)
12存在位(P)
13修改位(M)
14访问位(A)
15保护位(R/W)

5.3.2 快表(TLB)优化

  • TLB命中率公式

    有效访问时间 = TLB访问时间 + (1-命中率)×内存访问时间
  • 示例计算

    假设TLB访问10ns,内存访问100ns,命中率90%:
    有效时间 = 10 + (1-0.9)×(100+100) = 30ns
    (未使用TLB时为200ns)

5.4 分段存储管理

5.4.1 分段vs分页

特性分页系统分段系统
划分单位固定大小页(物理)逻辑段(程序结构)
地址空间一维线性二维(段号+段内偏移)
碎片无外部碎片有外部碎片
共享按页共享按段共享
保护页级保护段级保护(更精细)

5.4.2 段表结构

struct segment_descriptor {
    uint32_t base_addr;    // 段基址
    uint32_t limit;        // 段长度
    uint8_t present:1;     // 存在位
    uint8_t read_write:1;  // 读写权限
    uint8_t user_super:1;  // 用户/内核段
    // 其他控制位...
};

5.5 虚拟内存技术

5.5.1 请求分页机制

页表扩展字段

  • 状态位(P):是否在内存中

  • 访问字段(A):记录访问次数/时间

  • 修改位(D):页面是否被修改

  • 外存地址:页面在外存的位置

缺页中断流程

  1. 查页表发现P=0

  2. 触发缺页中断(内中断)

  3. 操作系统选择牺牲页

  4. 若D=1则写回磁盘

  5. 调入目标页,更新页表

  6. 重新执行引发中断的指令

5.5.2 页面置换算法

算法对比表

算法规则描述实现复杂度适用场景
OPT淘汰将来最久不使用的页不可实现理论基准
FIFO淘汰最先进入的页简单简单嵌入式系统
LRU淘汰最近最久未使用的页较高通用系统
CLOCK循环扫描,淘汰访问位=0的页中等实际系统常用
改进CLOCK同时考虑访问位和修改位较高要求高的系统

Belady异常

  • 现象:分配更多物理块反而导致缺页增加

  • 仅FIFO算法会出现

5.6 内存映射文件

5.6.1 传统文件访问vs内存映射

5.6.2 共享内存实现

  1. 进程A调用shmget()创建共享区

  2. 进程B通过相同key调用shmget()获取标识符

  3. 双方进程shmat()将共享区映射到各自地址空间

  4. 通过直接内存访问实现通信

5.7 存储保护机制

5.7.1 硬件支持

  • 基址-界限寄存器

    • 基址寄存器:存储进程起始物理地址

    • 界限寄存器:存储进程最大长度

    • 每次访问检查:物理地址 = 逻辑地址 + 基址,且逻辑地址 < 界限

  • MMU功能

    1. 地址转换

    2. 访问权限检查

    3. TLB管理

5.7.2 典型保护违规

  1. 越界访问:地址 ≥ 界限寄存器值

  2. 权限违规:写只读页/执行非代码页

  3. 非法操作:用户态执行特权指令

第六章 文件管理

6.1 文件系统基础

6.1.1 文件概念与属性

文件定义:存储在外部存储设备上的具有符号名的相关数据集合

文件属性

  • 基本属性:

    struct file_attr {
        char name[256];    // 文件名
        size_t size;       // 文件大小
        time_t create_time;// 创建时间
        time_t modify_time;// 修改时间
        mode_t permission; // 访问权限(rwx)
        uid_t owner;       // 所属用户
        gid_t group;       // 所属组
    };

  • 扩展属性:

    • 隐藏标志(Windows的hidden属性)

    • 系统标志(Linux的immutable属性)

    • 校验和(完整性验证)

6.1.2 文件类型

类型扩展名示例特点
普通文件.txt, .jpg包含用户数据
目录文件(无)组织其他文件的特殊文件
字符设备/dev/ttyS0按字符流访问的设备
块设备/dev/sda按数据块访问的设备
符号链接(ln -s创建)包含指向另一文件路径的指针
管道文件(mkfifo创建)进程间通信的先进先出队列

6.2 文件逻辑结构

6.2.1 无结构文件

  • 特点:字节流形式,无内部结构

  • 典型应用

    • 文本文件(源代码、配置文件)

    • 二进制可执行文件

  • 访问方式

    # 顺序访问示例
    with open('data.bin', 'rb') as f:
        while chunk := f.read(1024):  # 每次读取1KB
            process(chunk)

6.2.2 有结构文件

(1) 顺序文件
  • 定长记录

    struct employee {
        int id;          // 4字节
        char name[20];   // 20字节
        float salary;    // 4字节
    };  // 每条记录固定28字节
    • 随机访问公式:第i条记录位置 = i * record_size

  • 变长记录

    • 需要分隔符或长度前缀

    • 访问必须顺序进行(无法直接定位)

(2) 索引文件

二级索引结构

逻辑记录号 → 一级索引 → 二级索引 → 实际数据块

计算示例

  • 假设:

    • 块大小=4KB

    • 索引项=4B

    • 则每块可存1024个索引项

  • 最大文件长度:

    • 直接索引:12×4KB=48KB

    • 一级间接:1024×4KB=4MB

    • 二级间接:1024²×4KB=4GB

6.3 文件物理结构

6.3.1 连续分配

实现方式

  • 文件控制块记录:

    struct contiguous_file {
        int start_block;  // 起始块号
        int block_count;  // 占用块数
    };

特点

  • 优点:

    • 顺序访问性能最优(最少寻道时间)

    • 实现简单

  • 缺点:

    • 外部碎片严重

    • 文件扩展困难

6.3.2 链接分配

(1) 隐式链接
  • 文件分配表(FAT)结构:

    块号下一块指针
    0-1 (结束)
    14
    23
  • 访问第n块需要n次读操作

(2) 显式链接
  • FAT表内存缓存

    class FAT:
        def __init__(self, disk_size, block_size):
            self.table = [-1] * (disk_size // block_size)
        
        def allocate_chain(self, size):
            # 分配空闲块链
            pass

6.3.3 索引分配

混合索引示例

struct inode {
    int direct[12];    // 直接指针
    int single_indir;  // 一级间接
    int double_indir;  // 二级间接
    int triple_indir;  // 三级间接
};

最大文件计算(块大小=4KB,指针=4B):

  1. 直接块:12×4KB = 48KB

  2. 一级间接:(4KB/4B)×4KB = 4MB

  3. 二级间接:1024×4MB = 4GB

  4. 三级间接:1024×4GB = 4TB

6.4 目录管理

6.4.1 目录结构

(1) 单级目录
/
├── file1
├── file2
└── file3
  • 问题:命名冲突,无法组织复杂项目

(2) 树形目录
/
├── home/
│   ├── user1/
│   └── user2/
└── etc/
    ├── passwd
    └── network/
  • 支持绝对路径和相对路径

  • 每个目录是特殊的inode

6.4.2 目录操作

关键系统调用

// 创建目录
int mkdir(const char *path, mode_t mode);

// 删除目录
int rmdir(const char *path);

// 打开目录
DIR *opendir(const char *name);

// 读取目录项
struct dirent *readdir(DIR *dirp);

6.5 文件存储空间管理

6.5.1 空闲空间管理

(1) 空闲表法
class FreeSpaceTable:
    def __init__(self):
        self.blocks = [(0, 1024)]  # (起始块号, 连续块数)
    
    def allocate(self, size):
        # 首次适应算法
        for i, (start, count) in enumerate(self.blocks):
            if count >= size:
                del self.blocks[i]
                if count > size:
                    self.blocks.append((start+size, count-size))
                return start
        return -1  # 分配失败
(2) 位示图法

计算公式

  • 块号→位图位置:

    def block_to_bit(block_num):
        word = block_num // 32  # 假设字长32位
        bit = block_num % 32
        return (word, bit)

  • 磁盘空间需求:

    def bitmap_size(disk_size, block_size):
        bits_needed = disk_size / block_size
        return math.ceil(bits_needed / 8)  # 字节数

6.5.2 成组链接法(UNIX方案)

超级块结构

struct super_block {
    int free_block_count;      // 当前组空闲块数
    int free_stack[100];       // 空闲块栈
    int next_group;            // 下一组指针
};

6.6 文件共享与保护

6.6.1 共享方式

(1) 硬链接

(2) 符号链接

  • 特点:

    • 是独立的文件(有自己的inode)

    • 存储目标文件路径

    • 跨文件系统可用

6.6.2 访问控制

(1) 访问控制表(ACL)权限模型

bash

# Linux setfacl示例
$ setfacl -m u:alice:rw- file.txt
$ getfacl file.txt
# file: file.txt
# owner: bob
# group: staff
user::rw-
user:alice:rw-
group::r--
mask::rw-
other::r--
(2) 文件保护矩阵
用户/组文件A文件B目录C
user1rw-r----x
groupAr--rwxr-x
others---r-----

6.7 文件系统性能

6.7.1 磁盘缓存

缓存策略

  1. 预读(Read-ahead):

    // 内核预读算法示例
    if (sequential_access_pattern) {
        readahead(fd, next_blocks);
    }
  2. 延迟写(Delayed Write):

    • 修改先保存在缓存中

    • 定期或缓存满时同步到磁盘

6.7.2 磁盘调度

初始条件

  • 请求序列:[98, 183, 37, 122, 14, 124, 65, 67]

  • 磁头初始位置:53

  • 初始方向:向外(磁道号增大方向)


1. SCAN算法(电梯算法)

规则:磁头单向移动服务请求,直到磁盘最外圈(或最内圈)后反向。

调度过程

  1. 当前方向:向外(磁道号↑)

  2. 从53出发,向外移动,依次处理路径上的请求:

    • 53 → 65 → 67 → 98 → 122 → 124 → 183(到达最外圈后反向)

  3. 反向移动(向内),处理剩余请求:

    • 183 → 37 → 14(到达最内圈结束)

服务顺序
65 → 67 → 98 → 122 → 124 → 183 → 37 → 14

总寻道距离计算

|65-53| + |67-65| + |98-67| + |122-98| + |124-122| + |183-124| + |37-183| + |14-37|  
= 12 + 2 + 31 + 24 + 2 + 59 + 146 + 23  
= 299

2. SSTF算法(最短寻道时间优先)

规则:每次选择离当前磁头位置最近的请求。

调度过程

  1. 初始位置:53

    • 最近请求:65(距离12)

  2. 位置:65

    • 最近请求:67(距离2)

  3. 位置:67

    • 最近请求:37(距离30)或 98(距离31)→ 选择 37

  4. 位置:37

    • 最近请求:14(距离23)

  5. 位置:14

    • 最近请求:98(距离84)

  6. 位置:98

    • 最近请求:122(距离24)

  7. 位置:122

    • 最近请求:124(距离2)

  8. 位置:124

    • 最近请求:183(距离59)

服务顺序
65 → 67 → 37 → 14 → 98 → 122 → 124 → 183

总寻道距离计算

|65-53| + |67-65| + |37-67| + |14-37| + |98-14| + |122-98| + |124-122| + |183-124|  
= 12 + 2 + 30 + 23 + 84 + 24 + 2 + 59  
= 236 

3. C-SCAN算法(循环扫描)

规则:磁头单向移动服务请求,到达最外圈后直接跳回最内圈(不处理返回时的请求)。

调度过程

  1. 当前方向:向外(磁道号↑)

  2. 从53出发,向外移动,依次处理路径上的请求:

    • 53 → 65 → 67 → 98 → 122 → 124 → 183(到达最外圈)

  3. 直接跳回最内圈(0,假设最小磁道为0),继续向外处理剩余请求:

    • 0 → 14 → 37

服务顺序
65 → 67 → 98 → 122 → 124 → 183 → 14 → 37

总寻道距离计算

|65-53| + |67-65| + |98-67| + |122-98| + |124-122| + |183-124| + |0-183| + |14-0| + |37-14|  
= 12 + 2 + 31 + 24 + 2 + 59 + 183 + 14 + 23  
= 350

对比总结(基于本题)

算法服务顺序总寻道距离特点
SCAN65→67→98→122→124→183→37→14299到达端点才反向
SSTF65→67→37→14→98→122→124→183236最短寻道,但可能饥饿
C-SCAN65→67→98→122→124→183→14→37350单向移动,跳回最内圈

结论

  • SSTF 寻道距离最短(236),但可能导致饥饿。

  • SCAN299),适合高负载系统。

  • C-SCAN 提供更均匀的等待时间,但寻道距离较长。

第七章 设备管理

7.1 I/O系统概述

7.1.1 设备分类

按传输速率分类:
类型速率范围典型设备管理特点
低速设备<1KB/s键盘、鼠标以字符为单位传输
中速设备1KB/s-1MB/s打印机、扫描仪需缓冲管理
高速设备>1MB/s磁盘、网卡DMA或通道控制
按信息组织方式分类:

7.1.2 设备控制器功能

  1. 接口转换:将设备信号转换为标准电子接口

  2. 缓冲暂存:缓解I/O速度与CPU差异

  3. 错误检测:校验数据传输的正确性

  4. 地址识别:响应特定I/O端口或内存地址

7.2 I/O控制方式

7.2.1 四种控制方式对比

控制方式CPU介入程度数据传输单位典型应用场景硬件需求
程序轮询100%字节/字简单嵌入式系统状态寄存器
中断驱动每次传输字节/字键盘、鼠标中断控制器
DMA开始和结束数据块磁盘、网卡DMA控制器
通道控制几乎不介入一组数据块高性能存储系统专用I/O处理器

7.2.2 DMA工作流程

关键寄存器

  • MAR(内存地址寄存器)

  • DC(数据计数器)

  • CR(控制寄存器)

7.3 缓冲技术

7.3.1 缓冲类型

单缓冲
  • 特点:生产者与消费者必须交替使用

  • 问题:效率低(等待缓冲空闲)

双缓冲(乒乓缓冲)
  • 优势:实现生产者消费者并行

  • 应用:视频播放、数据采集

循环缓冲

7.3.2 缓冲池管理

数据结构设计

struct buffer_header {
    int device;
    int status;
    struct buffer_header *next;
    char *data;
};

struct buffer_pool {
    struct buffer_header *free_list;
    struct buffer_header *io_queue;
};

操作原语

  1. get_buf():从空闲链获取缓冲区

  2. put_buf():将缓冲区放回空闲链

  3. request():设备I/O请求排队

  4. release():完成I/O后释放

7.4 设备分配与回收

7.4.1 设备分配策略

静态分配
  • 特点:进程运行前分配所有所需设备

  • 优点:无死锁风险

  • 缺点:资源利用率低

动态分配
  • 安全分配

  • 银行家算法扩展:将设备作为一类资源纳入检测

7.4.2 设备分配过程

对于配备通道的计算机中,在进行设备分配时所需的数据结构有:设备控制表、控制器控制表、通道控制表和系统设备表等。

基本的设备分配程序

1) 分配设备: 根据物理设备名在SDT中找出该设备的DCT,若设备忙,便将请求I/O的进程PCB挂在设备队列上;否则,便按照一定的算法来计算本次设备分配的安全性,若不会导致系统进入不安全状态,便将设备分配给请求进程;否则,仍将其PCB插入设备队列。

2) 分配控制器: 分配设备给进程后,再到其DCT中找出与该设备连接的控制器的COCT。若控制器忙,便将请求I/O进程的PCB挂在该控制器的等待队列上;否则,将该控制器分配给进程。

3) 分配通道: 分配控制器后,再在COCT中找到与该控制器连接的CHCT。若通道忙,便将请求I/O的进程挂在该通道的等待队列上;否则,将该通道分配给进程。    

 只有在设备、控制器和通道三者都分配成功时,这次的设备分配才算成功;之后便可启动该I/O设备进行数据传送。

7.5 磁盘管理

7.5.1 磁盘调度算法(第六章讲过)

7.5.2 磁盘性能计算

访问时间组成

总访问时间 = 寻道时间 + 旋转延迟 + 传输时间
  • 典型值

    • 寻道时间:2-10ms

    • 旋转延迟(7200RPM):4.17ms(半圈)

    • 传输速率:200MB/s

示例计算
读取4KB数据块:

总时间 = 6ms(寻道) + 4.17ms(旋转) + (4KB/200MB/s) ≈ 10.19ms

7.6 设备驱动程序

7.6.1 驱动结构

struct device_driver {
    int (*init)(void);
    int (*open)(struct file *);
    int (*read)(struct file *, char *, int);
    int (*write)(struct file *, const char *, int);
    int (*ioctl)(struct file *, unsigned int, unsigned long);
    int (*release)(struct file *);
};

7.6.2 驱动加载流程

  1. 注册设备

  2. 初始化操作集

  3. 创建设备节点

7.7 关键问题解决方案

7.7.1 中断处理优化

两阶段处理

  1. 上半部(快速处理):

    • 在关中断环境下执行

    • 只做关键状态保存

    • 调度下半部处理

  2. 下半部(延迟处理):

    • 可中断环境下执行

    • 复杂的数据处理

    • 通过tasklet/workqueue实现

7.7.2 设备无关性实现

统一接口层设计

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值