OS-01 操作系统引论
OS-01 操作系统引论
一、操作系统的基本概念
操作系统是计算机系统中最基本的系统软件,它管理计算机的硬件资源,为应用程序提供运行环境,同时也是用户与计算机硬件之间的接口。操作系统的核心目标是方便用户使用和提高资源利用率。要理解操作系统,首先需要了解它经历了怎样的发展历程,以及不同类型操作系统的各自特点。
1.1 操作系统的发展与类型
操作系统的发展经历了从简单到复杂、从低效到高效的过程。最早期的计算机没有操作系统,用户直接使用机器语言编程,需要手动操作硬件。随着计算机的发展,操作系统的形态也在不断演进。
单道批处理系统是操作系统的雏形。它的工作方式是内存中只存放一道用户作业,CPU依次执行,直到当前作业完成才载入下一个。这种方式的优点是实现简单,但缺点也是致命的:当CPU在执行I/O操作时,只能等待,无法处理其他任务,导致CPU利用率极低。例如,一个需要频繁读磁盘的作业在执行时,CPU大部分时间都在空转等待。
多道批处理系统的出现是一个重大突破。它允许在内存中同时存放多道程序,当一个程序等待I/O时,CPU立即切换到另一个程序执行。这种"交替执行"的方式充分利用了CPU的计算能力。举例来说,假设三个作业A、B、C分别需要计算资源10秒和I/O操作5秒,单道批处理的总耗时是45秒(三个作业串行),而多道批处理可以通过重叠计算与I/O将总耗时压缩到大约25秒。但多道批处理的缺点在于作业的周转时间变长了,而且系统管理复杂度显著提高。
分时系统的出现解决了多道批处理缺乏交互性的问题。它通过时间片轮转的方式,让多个用户通过终端同时与计算机交互。每个用户获得一个短暂的时间片轮流使用CPU,由于时间片极短(通常为几十毫秒),每个用户都感觉自己在独占计算机。分时系统的核心指标是响应时间——用户发出指令到得到反馈的时间间隔。
实时系统则专注于满足严格的时间约束。它要求系统必须在规定的时间内对外部事件做出响应,这个截止时间是硬性的,错过了就可能导致灾难性后果。实时系统分为硬实时(如航空控制系统,必须严格遵守时间约束)和软实时(如视频播放,偶尔的超时不会造成灾难性后果)。
1.2 多道程序设计的核心概念
多道程序设计是现代操作系统的基础思想。它的本质是在内存中同时驻留多个程序,使它们交替执行,实现CPU与I/O设备的高度并行工作。
多道程序设计的优点非常突出:首先,它极大地提高了CPU的利用率——当一个程序在等待I/O时,CPU并不空闲,而是去执行另一个程序。其次,系统的吞吐量(单位时间内完成的作业数量)也得到了显著提升。然而,缺点同样不可忽视:单个作业的周转时间比单道系统更长,因为需要与其他作业共享CPU,系统的管理和调度也变得更加复杂。
理解并行和并发的区别是学习操作系统的第一道门槛。并行(Parallelism)是指多个事件在同一时刻真正同时发生,这需要系统具备多个处理器或处理器核心。并发(Concurrency)则是指多个事件在同一个时间间隔内交替发生,从宏观上看像是同时进行的,但实际上在单核处理器中,任何时刻都只有一个程序在执行。打个比方:并行就像两条并行的传送带同时在生产产品,而并发就像一个人在处理多个任务,通过快速地任务切换让人感觉所有任务都在"同时"推进。
一道常见的面试题:两个进程共享一个全局变量count(初始为0),每个进程都对count执行100次count++操作。在并发环境下,count最终的可能取值范围是什么?
count++在机器层面需要三条指令:LOAD count到寄存器、在寄存器中加1、STORE count回内存。当两个进程并发执行时,这三条指令可能以任意顺序交错。最好的情况是每次交错都完整执行,最终得到200。最差的情况是两个进程同时LOAD到相同的值,各自加1后写回,导致一次增加被"覆盖"。理论上极端情况下每次都被覆盖,最终结果为2。所以可能范围是 [2, 200]。
二、中断与异常
中断机制是现代操作系统的"心脏"。没有中断,操作系统无法响应外部事件,也无法实现多道程序设计的"交替执行"。
2.1 中断与异常的分类和区别
中断(Interrupt)和异常(Exception)虽然都会导致CPU暂停当前程序转去执行特定处理程序,但它们的根本来源不同。
中断是由CPU外部的事件引起的。典型的例子包括:磁盘I/O完成、键盘被按下、鼠标移动、网卡收到数据包、时钟芯片产生的定时中断等。这些事件的共同特点是它们来自CPU外部,是不可预测的异步事件。
异常则是由CPU内部的事件引起的,通常是正在执行的指令本身出现了问题。例如:程序执行了除零操作、访问了非法的内存地址、执行了不在指令集中的无效操作码、调用了系统调用指令。异常是与当前指令同步的,也就是说,如果重新执行同样的指令,同样的异常会再次发生。
判断一个事件是否中断还是异常的方法是看它的来源:来自外部设备的是中断,来自CPU内部的是异常。
2.2 中断处理过程
当中断发生时,CPU需要暂停当前程序的执行,转去处理中断事件,处理完成后再回到原来的程序继续执行。这个过程的完整步骤是:
第一步,关中断。在保存现场的过程中,CPU不能再响应其他中断,否则可能导致保存的现场数据不一致。
第二步,保存现场。将当前程序的程序计数器(PC)、程序状态字(PSW)、寄存器等关键信息保存到栈中,以便后续恢复。
第三步,识别中断源。CPU需要判断是哪个设备发出了中断,这个过程通常通过查询中断向量表来完成。
第四步,执行中断处理程序。根据识别出的中断类型跳转到对应的处理函数执行。
第五步,恢复现场。中断处理完成后,将之前保存的现场数据恢复到寄存器中。
第六步,开中断并返回。重新开启中断响应能力,通过iret指令(x86架构)返回到被中断的程序继续执行。
三、CPU的两种运行状态
为了保护操作系统不被用户程序破坏,CPU设计了两种运行状态:内核态(又称管态、系统态)和用户态(又称目态)。
内核态是操作系统运行时的状态。在内核态下,CPU可以执行所有指令,包括特权指令。特权指令是那些可能破坏系统稳定性的指令,如修改内存管理单元(MMU)、设置时钟、清除内存、修改PSW等。操作系统内核负责管理这些关键资源,所以它必须运行在内核态。
用户态是普通用户程序运行时的状态。在用户态下,CPU只能执行非特权指令,不能执行前述的特权指令。如果用户程序在用户态下试图执行特权指令,CPU会产生一个异常(称为"保护异常"),由操作系统接管处理。
状态转换的机制:
从用户态切换到内核态只有三种途径:系统调用、中断和异常。这三种方式的共同特点是用户程序主动或被动地"陷入"内核。转换是通过硬件机制完成的,用户程序无法直接修改CPU的状态寄存器来进入内核态,这保证了操作系统的安全性。
从内核态切换回用户态只有一种方式:由操作系统执行特权指令来修改PSW中的状态位,实现从内核态到用户态的转换。这个转换是操作系统主动进行的,发生在系统调用或中断处理完成后。
一个直观的例子:当你在应用程序中调用read()函数读取文件时(用户态),read()会触发系统调用指令,CPU切换到内核态,由文件系统驱动在内核态下执行实际的磁盘读取操作,读取完成后操作系统修改PSW,CPU返回用户态,应用程序继续执行。
四、系统调用
系统调用是操作系统提供给用户程序的服务接口。当用户程序需要执行需要特权的操作时(如读写文件、创建进程、分配内存),它无法直接在用户态完成,而是通过系统调用请求操作系统代为执行。
系统调用的处理过程:
- 用户程序调用库函数(如C语言中的printf),库函数将参数整理好
- 库函数执行一条访管指令(trap指令),触发CPU从用户态切换到内核态
- 操作系统根据系统调用号找到对应的内核处理函数
- 内核函数在内核态下执行所需操作
- 操作完成后,CPU返回用户态,结果返回给用户程序
需要系统调用的常见操作:文件操作(打开、读写、关闭)、进程管理(创建、终止)、内存管理(申请、释放)、设备操作(读键盘、写显示器)、网络通信等。
五、操作系统结构
操作系统本身也是一个软件,它的内部组织结构直接影响到系统的可靠性、可维护性和性能。
| 结构类型 | 特点 | 典型系统 | 评价 |
|---|---|---|---|
| 简单结构 | 没有清晰分层,模块间可以互相调用 | MS-DOS、早期UNIX | 效率高但维护困难,一处修改可能影响全局 |
| 分层结构 | 分为若干层,每层只依赖下层提供的服务 | THE系统 | 结构清晰,便于调试,但层间通信开销大 |
| 微内核 | 内核只保留最基本的功能(进程通信、最小调度) | Minix、QNX | 可靠性高,扩展性好,但性能开销较大 |
现代主流操作系统(Linux、Windows)采用混合结构,将性能关键的模块放在内核中运行,同时通过模块化机制保持了一定的灵活性和可维护性。
六、例题精讲
判断题:以下事件分别属于中断还是异常?
- 硬盘DMA传输完成 → 中断(外部设备事件)
- 程序发生段错误 → 异常(CPU内部检测到的非法访问)
- 定时器到期 → 中断(外部时钟硬件)
- 整数除零 → 异常(算术运算异常)
- 用户按下Ctrl+C → 中断(键盘输入事件)
- 缺页 → 异常(CPU访问内存时发现页面不在内存)
简答题:系统调用与普通函数调用的区别是什么?
系统调用需要CPU状态切换(用户态→内核态→用户态),而普通函数调用在用户态内完成。系统调用有较大的开销(数百个CPU周期),因为它涉及状态保存、特权级切换、返回等操作。普通函数调用仅涉及栈操作,开销很小(数个CPU周期)。