操作系统复习(九)

📅 2026/7/5 1:31:35
操作系统复习(九)
操作系统复习九IO软件的四个层次I/O软件通常自下而上分为以下四个层次1. 中断处理程序底层功能位于最底层当I/O操作完成或出错时负责响应和捕获中断保存被中断进程的CPU现场唤醒等待该I/O完成的驱动程序并恢复现场。2. 设备驱动程序功能直接与硬件设备控制器交互。将上层发出的抽象I/O请求如“读数据”翻译成具体的设备寄存器操作命令如向控制寄存器写指令、向数据寄存器读写数据。3. 设备独立性软件设备无关I/O软件功能向上层提供统一的标准接口屏蔽底层硬件差异。主要负责设备命名、缓冲管理如设置缓冲区、错误报告以及对独占设备的逻辑分配如SPOOLing技术的实现。4. 用户层I/O软件最高层功能运行在用户态是连接应用程序与内核的接口。通常以**库函数如C语言的printf、scanf、fread**形式存在负责将用户数据格式化后通过系统调用陷入内核触发后续的I/O操作。补充记忆口诀自底向上中中断 驱驱动 独独立 用用户—— 硬件最近的是中断离用户最近的是库函数。现代操作系统如Linux严格遵循此分层架构以实现I/O功能的高内聚和低耦合。通道程序通道程序是I/O通道一种专用于控制输入/输出的小型处理器所执行的指令序列。它本质上是“写给通道看的程序”用来精确控制数据的传输路径、内存位置和传输长度。你可以把它理解为CPU 给 I/O 通道下发的“详细操作清单”。CPU 只需把这份清单的起始地址告诉通道通道就会独立地、自动地按清单逐条执行直到所有数据传输完毕才中断通知 CPU。1. 通道程序的组成在经典的 IBM 大型机或现代操作系统原理教材中通道指令通常被称为CCWChannel Command Word通道命令字。一条典型的通道指令包含以下核心字段命令码Command指明要做什么如“读”、“写”、“控制”、“转移”。数据主存地址Data Address指明本次传输的数据在内存中的起始位置。传输字节数Count指明本次传输的数据长度。标志位Flags指明指令执行完毕后的动作如“结束中断”、“链式执行”等。多条这样的 CCW 排列在一起就组成了通道程序。2. 通道程序的执行流程编写与提交操作系统在内存中构建好通道程序即一连串 CCW。启动通道CPU 执行“启动 I/O”指令将通道程序的首地址告诉通道控制器。并行运作关键通道从内存取出第一条 CCW开始控制硬件传输数据。此时CPU 与 I/O 通道并行工作——CPU 去执行其他计算任务通道负责搬运数据。结束处理当通道执行完最后一条指令或遇到错误会通过中断信号通知 CPU“数据传输完毕请来验收”。3. 通道程序 vs CPU 程序这是理解它的关键避免混淆运行主体不同CPU 程序由 CPU 执行通道程序由I/O 通道专门的外设处理器执行。指令集不同CPU 指令负责加减乘除、逻辑判断通道指令只负责“把某段内存的数据搬到某设备”或“从设备搬回内存”它没有运算、跳转等复杂逻辑通常仅支持顺序执行或简单的链式转移。存在位置通道程序存储在内存中但由通道直接去内存取指执行类似 DMA但拥有更强的指令解析能力。4. 为什么要引入它这是为了解决“程序控制 I/O”和“中断驱动 I/O”的缺陷如果每次传输一个字节都要 CPU 干预CPU 会被拖死。引入通道程序后CPU 只需发出一次“启动”命令剩下的成千上万个字节的搬运工作全部由通道程序自动管理。这实现了I/O 操作与 CPU 计算的高度并行是早期大型机实现高吞吐量的核心技术。现代 PC 中还有吗在 PC 体系中这种“通道程序”的概念被高度简化为DMA直接内存访问控制器的描述符链Descriptor Chain。现代 NVMe 固态硬盘或网卡使用的**环形缓冲区Ring Buffer和PRP物理区域页**列表本质上就是“通道程序”的变种——依然是 CPU 告诉硬件“去这里读、传到哪里、长度多少”的指令清单。进程间通信机制进程间的通信机制IPCInter-Process Communication是操作系统为隔离的进程之间提供的数据交换通道。由于进程拥有独立的地址空间它们无法直接访问对方的内存必须借助操作系统提供的特定机制。根据通信效率和数据量IPC 机制可以分为以下几大类1. 管道通信Pipe管道本质是内核维护的环形缓冲区以无格式字节流方式传输数据。匿名管道Pipe仅在父子进程或兄弟进程有亲缘关系间使用。通过pipe()系统调用创建一端写、一端读数据被消费后即从缓冲区消失。命名管道FIFO通过磁盘上的特殊文件mkfifo存在允许任意两个进程无亲缘关系通过打开该文件进行通信。缺点是单向传输如需双向需建立两个管道。2. 信号Signal信号是软件中断用于通知进程发生了某个异步事件如按 CtrlC、非法内存访问。特点信息量极小仅传递一个预定义的整数编号且不携带用户数据。它主要用于进程间控制如终止进程SIGKILL、暂停SIGSTOP而非大规模数据传输。3. 消息队列Message Queue消息缓冲机制的正式名称。进程通过系统调用将数据打包成有格式的消息块带有类型标识发送到内核维护的消息队列中。优点有边界读端可以根据消息类型直接提取特定消息无需按顺序读取克服了管道的字节流模糊性。缺点数据需要在用户态和内核态之间拷贝两次传输长度受限效率中等。4. 共享内存Shared Memory操作系统将同一块物理内存区域映射到不同进程的虚拟地址空间中使它们可以直接读写这片区域。优点最快的通信方式。数据只需在写入时拷贝一次到共享区其他进程立即可见无需内核介入拷贝。致命缺点缺乏同步机制。如果两个进程同时修改同一块数据会发生数据错乱。因此必须配合信号量Semaphore来保证互斥访问。5. 信号量Semaphore严格来说信号量不负责传输数据它属于同步工具PV操作。它用于控制多个进程对共享资源如共享内存的访问权限。它是一个整数计数器P操作申请减1V操作释放加1。值大于0表示可用资源数值等于0表示资源被占满进程需阻塞等待。6. 套接字Socket套接字允许通信双方跨越物理网络边界。类型流式套接字TCP面向连接可靠和数据报套接字UDP无连接不可靠。本地使用在 Linux 中Unix Domain SocketUDS常用于本机高性能进程通信它不走网络协议栈效率介于管道和共享内存之间且支持双向、带边界的数据传输。效率与选择建议核心总结通信机制数据拷贝次数数据边界使用场景管道Pipe2次内存→内核→内存字节流无边界Shell命令拼接、简单父子进程传输消息队列2次内存→内核→内存有边界按类型取需要格式化的短消息、任务分发共享内存1次写入共享区即可无裸内存块大数据量、高频读写视频帧、数据库缓存Socket本地UDS2次有协议栈开销有边界数据报或流TCP跨语言服务调用如 Nginx 与 PHP-FPM现代高性能系统如 Redis、Kafka的典型搭配是共享内存存数据 信号量锁保护达到极限吞吐而跨机器的分布式通信则依赖Socket 序列化协议如 Protobuf。索引节点inode多级指针表示文件每个inode表示一个文件【文件偏移量 → 逻辑块号 L每块 8KB】 | 【判断 L 落在哪个区间】 | ┌─────────────┼──────────────────────────────┐ ↓ ↓ ↓ 【直接区】 【间接区】 【二次/三次间接区】 (L 0 ~ 14) (L 15 ~ 2062) (L 2063 ...) ★ 寻址总结构图INODE 与索引块的层级关系 ┌────────────────────────────────────────────┐ │ INODE (128 字节) │ │ ┌──────────────────────────────────────┐ │ │ │ 状态信息 (68 字节) │ │ │ └──────────────────────────────────────┘ │ │ ┌──────────────────────────────────────┐ │ │ │ 直接指针 0 ──────→ (指向数据块) │ │ │ │ 直接指针 1 ──────→ (指向数据块) │ │ │ │ ... │ │ │ │ 直接指针 14 ──────→ (指向数据块) │ │ ← 共 15 个 │ ├──────────────────────────────────────┤ │ │ │ 指针[15] 一次间接 ─→ [一级索引块] │ │ │ │ 指针[16] 二次间接 ─→ [二级索引块] │ │ │ │ 指针[17] 三次间接 ─→ [三级索引块] │ │ │ └──────────────────────────────────────┘ │ └────────────────────────────────────────────┘ │ │ 每个索引块大小为 8KB │ 每个指针 4 字节 → 每块可存 2048 个指针 ↓ ① 直接指针区 (0 ~ 14) INODE ┌──────┐ │ 直接0 │────→ ┌──────────┐ │ 直接1 │────→ │ 数据块 │ │ ... │ │ (物理号) │ │ 直接14│────→ └──────────┘ └──────┘ 特点1 次 I/O 就能读到数据适合小文件。 ② 一次间接指针 (第 15 号槽) INODE 一级索引块 (8KB) 数据块 ┌──────┐ ┌─────────────────────────────┐ │指针[15]│──────────→│ 指针[0] ──────────────────→│ 数据块 0 │ └──────┘ │ 指针[1] ──────────────────→│ 数据块 1 │ │ 指针[2] ──────────────────→│ 数据块 2 │ │ ... │ ... │ │ 指针[2047]─────────────────→│ 数据块2047│ └─────────────────────────────┘ 覆盖逻辑块号15 ~ 2062 (共 2048 块) → 大小 16 MB 需要 2 次 I/O读索引块 读数据块 ③ 二次间接指针 (第 16 号槽) INODE 二级索引块 (8KB) 一级索引块 (8KB) 数据块 ┌──────┐ ┌────────────────────┐ ┌─────────────────┐ │指针[16]│─────→│ 指针[0] ──────────→│ │ 指针[0] ────────→│ 数据块 │ └──────┘ │ 指针[1] ──────────→│ │ 指针[1] ────────→│ 数据块 │ │ ... │ │ ... │ ... │ │ 指针[2047]────────→│ │ 指针[2047]──────→│ 数据块 │ └────────────────────┘ └─────────────────┘ 覆盖逻辑块号2063 ~ 20632048²-1 (共 2048² 4,194,304 块) → 大小 32 GB 需要 3 次 I/O读二级块 读一级块 读数据块 ④ 三次间接指针 (第 17 号槽) INODE 三级索引块 二级索引块 一级索引块 数据块 ┌──────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │指针[17]│─────→│指针[0] ──→│ │指针[0] ──→│ │指针[0] ──→│ 数据块 │ └──────┘ │指针[1] ──→│ │指针[1] ──→│ │指针[1] ──→│ 数据块 │ │ ... │ │ ... │ │ ... │ ... │ │指针[2047]→│ │指针[2047]→│ │指针[2047]→│ 数据块 │ └──────────┘ └──────────┘ └──────────┘ 覆盖大小2048³ 8,589,934,592 块 → 64 TB 需要 4 次 I/O三级块 二级块 一级块 数据块一些题目114、最短作业优先调度算法其作业平均周转时间最短。 对 2