欢迎来到系统软件(A Level 9618)
你好,未来的计算机科学家!本章系统软件将带你揭开幕布,看看计算机在后台到底是如何运作的。
我们通常会想到各种应用程序(即应用软件),但如果没有强大的系统软件在背后管理一切,这些程序都无法运行。在 A Level 阶段,我们将深入研究操作系统 (OS) 的运行机制,以及语言翻译程序所使用的重要流程。
别担心,“分页”或“词法分析”这些概念听起来很复杂——我们将通过简单的类比来拆解它们,确保你掌握考试所需的这些核心知识!
16.1 操作系统的目的 (OS)
什么是操作系统?
操作系统 (OS) 是管理所有计算机资源(CPU、内存、文件和外设)的总控程序。它充当了硬件与用户/应用程序之间的中间人。
OS 功能 1:最大化资源利用与隐藏复杂性
操作系统的首要工作是最大化资源利用率(如 CPU 时间和内存空间)。
- 用户界面: 操作系统提供用户界面(如 Windows 或 macOS),让你能够通过简单的图标和菜单与计算机进行交互。这个界面隐藏了硬件的复杂性。
- 类比: 想象一下驾驶汽车。你只需要使用方向盘和踏板(界面)。你不需要了解内燃机的复杂物理原理或齿轮是如何啮合的(隐藏的硬件复杂性)。
OS 功能 2:进程管理(多任务处理)
当你打开多个程序(例如:播放音乐、写论文、运行计算)时,操作系统通过进程管理来处理这些并发任务。
进程 (Process) 就是当前正在运行的程序。操作系统使用多任务处理 (Multi-tasking) 让所有进程看起来像是在同时运行,但实际上,CPU 是在它们之间快速切换。
进程状态
一个进程可能处于以下三种基本状态之一:
- 运行 (Running): 进程当前正在 CPU 上执行指令。(在任何时刻,每个 CPU 核心只能真正运行一个进程)。
- 就绪 (Ready): 进程已准备好执行,但正在等待 CPU 可用。
- 阻塞 (Blocked): 进程无法继续,因为它在等待某个外部事件发生(例如:等待键盘输入或从硬盘读取数据)。
小技巧: 记住 R-R-B(Running, Ready, Blocked)。
调度 (Scheduling) 的必要性
为了管理下一个获得 CPU 使用权的进程,操作系统会使用调度程序 (Scheduler) 和调度例程。调度的目标通常是最大化吞吐量、确保公平性并减少响应时间。
你需要理解以下调度算法的功能及其优缺点:
- 轮询调度 (Round Robin, RR): 每个进程在 CPU 上获得固定的、很短的时间片 (quantum)。如果时间片用完,进程将移动到队列末尾。
- 优点: 对交互式用户而言,具备极佳的公平性和响应时间。
- 短作业优先 (Shortest Job First, SJF): 预计执行时间最短的进程优先运行。
- 优点: 最大化吞吐量(能快速完成更多任务)。
- 先来先服务 (First Come First Served, FCFS): 最先请求 CPU 的进程获得优先权。
- 优点: 实现简单;非常公平(不会出现饥饿现象)。
- 最短剩余时间 (Shortest Remaining Time, SRT): SJF 的抢占式版本。如果新到达的任务总时间比当前运行任务的剩余时间短,新任务会抢占 CPU。
- 优点: 比 SJF 具有更高的吞吐量。
OS 功能 3:内核与中断
内核 (Kernel) 是操作系统的核心组件。它在计算机启动时首先被加载,负责处理最关键的底层任务,如内存管理和中断处理。
内核充当中断处理程序 (Interrupt Handler)。中断 (Interrupt) 是发送给 CPU 的信号,用于临时停止当前正在运行的进程,以便 CPU 处理高优先级事件(如磁盘错误、I/O 完成或定时器信号)。
- 当中断发生时,内核会保存当前运行进程的状态(使用程序计数器 PC 和累加器 ACC 等寄存器)。
- 内核识别中断类型。
- 执行相应的中断服务例程 (ISR)。
- ISR 完成后,内核恢复原始进程的状态,进程从中断处继续执行。
OS 功能 4:虚拟内存、分页与分段
虚拟内存 (Virtual Memory) 是一种技术,操作系统利用辅助存储器(硬盘)来模拟额外的 RAM,从而允许运行比物理 RAM 更大的程序。
操作系统管理内存(特别是虚拟内存)的两种主要方法是分页和分段:
分页 (Paging)
- 概念: 主存 (RAM) 被划分为固定大小的块,称为页框 (Page frames)。程序被划分为固定大小的块,称为页 (Pages)。
- 当程序需要内存时,页面会在磁盘和 RAM 之间交换。
分段 (Segmentation)
- 概念: 程序被划分为逻辑上大小不等的块,称为段 (Segments)(例如:一个段存放主程序代码,一个存放数据,一个存放子程序)。
- 段在磁盘和 RAM 之间交换。
- 区别: 页是物理的且大小固定;段是逻辑的且大小可变。
磁盘抖动 (Disk Thrashing)
这是一个关键术语!如果操作系统花费在页面/段在 RAM 和硬盘之间交换的时间,比执行程序指令的时间还要多,这被称为磁盘抖动。
- 结果: 系统速度大幅下降,因为 CPU 持续在等待缓慢的磁盘访问。
- 页面置换: 如果操作系统需要空间给新页面,它必须替换现有的页面,通常选择最近未使用的页面(最近最少使用算法 – LRU),以避免换出频繁需要的页面。
A Level 的侧重点在于多任务处理和内存管理的*机制*。请记住三个进程状态 (R-R-B),以及分页(固定、物理)与分段(可变、逻辑)之间的核心区别。
16.2 翻译软件
源代码(由人类使用高级语言如 Python 编写)必须转换为机器码(二进制指令),CPU 才能执行。这就是翻译软件的任务。
回顾:汇编程序、编译程序与解释程序
- 汇编程序 (Assembler): 将汇编语言(低级、人类可读的指令)翻译成机器码。
- 编译程序 (Compiler): 在执行之前将整个高级语言程序翻译成机器码。生成可执行文件。(属于 AS Level 内容,但它是核心先决知识)。
- 解释程序 (Interpreter): 逐行翻译并执行高级语言程序。它*不会*生成独立的翻译版本。
你知道吗? 像 Java(控制台模式)这样的语言采用了混合方式:它们首先被编译成中间字节码,然后由 Java 虚拟机 (JVM) 进行解释。这就是为什么有些程序被描述为部分编译、部分解释的原因。
编译过程:四个阶段(A-Level 深度)
程序编译时会经历几个不同的阶段,以确保程序的正确性和效率。
第 1 阶段:词法分析 (Lexical Analysis)
- 目的: 将源代码分解为有意义的单位,称为标记 (Tokens)。
- 去除注释和空格。
- 识别关键字(如
IF,WHILE)、标识符(变量名)、常量和运算符。 - 标记存储在符号表 (Symbol table) 中。
- 类比: 阅读句子并识别单词,按空格将它们分开。
第 2 阶段:语法分析 (Syntax Analysis)
- 目的: 根据语言的语法规则检查程序结构。
- 使用第 1 阶段生成的标记来构建语法树 (Parse tree)(或抽象语法树)。
- 如果发现错误(如缺少分号或括号),编译器会停止并报告语法错误。
- 类比: 检查句子结构在语法上是否正确(例如:“猫坐在垫子上”是正确的,而“猫子垫在坐上”则是语法错误)。
第 3 阶段:代码生成
- 目的: 如果语法正确,编译器会将语法树翻译成中间代码,并最终生成目标机器码(或汇编代码)。
第 4 阶段:优化
- 目的: 检查生成的机器码,使其运行更快或占用内存更少(即提高效率)。
- 示例: 如果一个变量被赋值但后续从未被使用,优化器可能会删除那行代码。
表达语言语法
为了执行语法分析,编译器需要描述合法程序外观的精确规则。这些规则被称为语言的语法,并使用形式化方法表示:
巴科斯-诺尔范式 (BNF)
BNF 是一种元语言(用于描述另一种语言的语言),用于表达编程语言的语法。
- 使用
::=(定义为)、|(或)以及尖括号< >表示非终结符(需要进一步定义的元素)。 - 示例:
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
语法图 (Syntax Diagrams)
语法图是语法规则的图形表示。它们像流程图一样,显示了构建语言有效部分(如有效的标识符或循环结构)必须遵循的路径。
- 优点: 与 BNF 相比,人类通常更容易阅读和遵循。
逆波兰表示法 (RPN)
在计算数学表达式时,计算机更倾向于使用一种无需括号和运算符优先级规则(BODMAS/BIDMAS)的方法。这种方法就是逆波兰表示法 (RPN),也称为后缀表示法。
在 RPN 中,运算符跟在操作数(数字)之后。
- 标准(中缀): \(10 + 5\)
- RPN(后缀): \(10 \ 5 \ +\)
RPN 如何求值(使用栈):
RPN 表达式通过栈 (Stack)(一种后进先出数据结构)来计算。
- 从左到右扫描表达式。
- 如果项是数字(操作数),则将其压入栈中。
- 如果项是运算符,则从栈中弹出必要数量的操作数(通常是两个),执行运算,并将结果推回栈中。
示例演示: 计算 \(5 \ 3 \ + \ 2 \times\)
第 1 步: 压入 5。栈:[5]
第 2 步: 压入 3。栈:[5, 3]
第 3 步: 运算符 '+'。弹出 3 和 5。计算 \(5 + 3 = 8\)。压入 8。栈:[8]
第 4 步: 压入 2。栈:[8, 2]
第 5 步: 运算符 '\(\times\)'。弹出 2 和 8。计算 \(8 \times 2 = 16\)。压入 16。栈:[16]
结果: 16
优点: 表达式按照读取顺序直接计算,简化了编译器内部计算所需的代码。
请记住编译的顺序(词法 -> 语法 -> 代码生成 -> 优化)。理解 RPN 使用栈来计算表达式而无需括号,这对高效的计算机处理至关重要。