OS01 绪论
type
status
date
slug
summary
tags
category
icon
password
写在前面
这是笔者2025年春季学期在操作系统(实验班)上的课堂笔记,经LLM整理后的产物;尚未经过人工整理和校对,内容仅供参考。
绪论
- 答疑:周五16-17
- lab附加design doc
- 评分:
- 参与:5%
- 5 labs:30%(4%+6*6.5%)
- design doc + code
- 独立完成、助教讲解、无额外作业
- 期中25%,期末40%
什么是操作系统
操作系统是一种系统软件,它的核心作用是作为用户应用程序与计算机硬件之间的桥梁。它允许应用程序以更简单、更统一的方式使用复杂的硬件资源,而无需关心底层的具体细节。
操作系统的主要功能可以概括为几个方面。首先,它提供简单易用的抽象,将复杂的硬件操作封装成清晰的接口。例如,文件系统抽象了磁盘块的读写操作,进程和线程抽象了程序的执行,虚拟内存抽象了物理内存的使用,而容器则进一步抽象了操作系统环境本身。其次,操作系统负责管理并保护共享资源,确保多个应用程序可以安全、公平地使用CPU、内存、存储设备等,防止它们相互干扰。此外,操作系统还肩负着确保安全性和进行验证的责任,它会检查访问请求的合法性。最后,操作系统为进程之间、计算机之间提供了通信机制。
一个进程是程序的一次执行实例,它由几个关键要素构成。第一个要素是一个独立的地址空间,这是进程可以使用的内存范围。第二个要素是在该地址空间内运行的一个或多个线程,线程是真正的执行流。除此之外,进程还包含其他关联的系统状态,例如打开的文件表、网络连接(Socket)等。
操作系统为进程提供了至关重要的保护、隔离和资源共享机制。它确保一个进程无法随意访问或破坏另一个进程的内存空间,从而实现隔离。同时,它又允许进程在受控的前提下共享某些资源,如磁盘文件。值得注意的是,操作系统内核自身也作为一个受保护的实体,与其他用户进程相隔离。
最后,操作系统还提供了一系列公共服务,这些服务可以被所有应用程序使用,从而避免了重复开发。这些公共服务包括持久化存储管理、图形窗口系统、网络协议栈以及各种共享库等。
操作系统简史
操作系统的发展与计算机硬件形态的演变紧密相连,大致可以分为三个时代。
第一个是大型机时代。这个时代的代表是像ENIAC这样的庞然大物。随后出现的Multics系统雄心勃勃,虽然本身不算非常成功,但它深刻地影响了后来的操作系统设计。
第二个是PC时代。随着个人电脑和工作站的普及,操作系统开始面向个人用户。图形用户界面(GUI)的出现,如苹果Macintosh和微软Windows的系统,极大地降低了计算机的使用门槛。
第三个是微型机时代。现在我们进入了以智能手机、可穿戴设备和物联网设备为代表的时代,操作系统也随之变得更加微型化、低功耗和互联化。
这些时代的变迁直接推动了操作系统技术的演进。从早期的批处理系统,到允许多个程序同时驻留内存的多道程序技术,再到支持一个程序内多个执行流的多线程技术,以及革命性的图形界面,操作系统的功能越来越复杂。其代码规模也从最初的数万行激增到现代操作系统的数千万行之多。
操作系统的演进过程呈现出清晰的谱系。UNIX系列始于Multics项目,后来演变为AT&T UNIX,并派生出BSD UNIX(伯克利版)和SunOS等。Apple系列的操作系统核心是Mach微内核与BSD代码的结合,历经NextStep,发展成为今天的XNU内核,支撑着macOS和iOS。Linux系列则源于林纳斯·托瓦兹受MINIX启发而开发的Linux内核,如今已成为Android、Chrome OS以及Ubuntu、Debian等众多发行版的基础。Windows系列从简单的MS-DOS起步,经过Windows 3.1,到采用全新设计的NT内核,之后演化出Windows 98、XP、Vista直至现在的Windows 10/11。
操作系统四个主要概念
线程
线程是操作系统调度的基本单位,可以理解为一个独立的执行上下文。每个线程都拥有自己的一套寄存器状态(包括程序计数器PC和条件码CC等)和一个专用的栈。
程序计数器(PC)始终指向下一条将要执行的指令地址。而其他特定的寄存器则共同维护着线程的运行时状态,例如栈指针(SP)就专门用于指示当前线程栈的顶部位置。除了寄存器中的状态,线程的一部分运行时数据也会存储在内存中。线程这一抽象的核心价值在于它封装了并发执行的能力,使得多个任务可以“同时”向前推进。
地址空间
地址空间是一个关键抽象,它让程序仿佛运行在一个独立、连续的内存空间上,而这个空间与实际的物理内存布局是解耦的。
地址空间本质上是程序被允许访问的所有地址的集合,以及这些地址对应的访问状态(如可读、可写、可执行)。程序对任何一个地址的读写操作都会受到操作系统的严密监控。在一个典型的地址空间布局中,栈通常从高地址向低地址增长,主要用于存储函数调用的临时变量和返回地址;而堆则从低地址向高地址增长,用于存放程序运行时动态分配的数据。地址空间这一抽象的核心目的是实现保护,确保一个程序无法干扰其他程序或操作系统本身的内存数据。
进程
进程代表了一个正在运行的程序的实例。它不仅仅是一段静态的代码,而是一个动态的执行环境,这个环境包含了一个独立的地址空间以及在其中运行的一个或多个线程。
进程可以被看作是一个拥有严格权限限制的执行容器。它负责向操作系统申请各种资源,例如地址空间、文件描述符、文件系统访问权等,然后交由它内部的线程去实际执行代码。属于同一个进程的多个线程会共享该进程的绝大部分资源,包括代码段、全局数据段、堆以及打开的文件表等。
进程模型的优势在于提供了强大的隔离性,安全性好。但缺点是效率相对较低,因为创建进程、销毁进程以及在进程间通信(IPC)的开销都比较大,通信机制也更复杂。需要注意的是,同一个程序(如同时打开两个Word文档)是可以对应多个独立的进程实例的。
双模式操作(用户态/内核态)
现代处理器通常至少支持两种运行模式:用户态和内核态(也称为系统态或保护态)。这种硬件级别的区分是操作系统实现保护的基础,只有运行在内核态下的代码才有权限执行某些特权指令或访问关键的硬件资源。
硬件上通常有一个特殊的模式位(Mode Bit)来标识当前CPU正处于哪种模式。当需要从用户态切换到内核态时(例如通过系统调用、中断或异常),硬件会自动保存用户态的程序计数器(PC)等状态,以便后续能够正确返回。执行内核态代码时必须非常小心地保存和恢复用户态的全部状态。
触发模式切换的典型事件包括:系统调用(进程主动请求操作系统服务,类似于远程过程调用RPC)、中断(由外部异步事件引发,如定时器到期或I/O完成)、异常/陷阱/故障(由程序内部同步事件引发,如除零错误或页错误)。这些事件的处理程序入口地址通常由一个叫做中断向量表的数据结构来维护。
从内核态返回用户态时,需要恢复之前保存的用户态上下文,并将程序计数器(PC)指向用户程序的下一条指令,这个过程通常通过执行特定的返回指令(如
rtn
或rfi
)来完成。程序的执行
当一个程序被启动时,操作系统会执行一系列步骤来为其创建运行环境。首先,操作系统会将可执行文件中的各个段(如代码段、已初始化数据段等)加载到内存的指定位置。接着,它会为程序创建运行时所需的堆区和栈区。完成这些准备工作后,操作系统将控制权转移给程序的入口点(如main函数)。
在此之后,操作系统的角色转变为后台的服务提供者和守护者。它负责响应程序的请求(通过系统调用),同时严密地保护操作系统自身以及其他程序不受该程序的非法操作影响。在CPU层面,程序的执行就是周而复始地重复三个基本阶段:取指(从内存获取指令)、译码(解析指令含义)和执行(完成指令操作)。
多道程序
多道程序,即允许多个进程同时驻留在内存中并交替执行的技术,是现代操作系统的基石。根据对内存的管理方式,可以将其分为两种类型。
朴素多道程序
这种方法实现了对CPU的虚拟化,但尚未对内存进行虚拟化保护。
其核心思想是时分复用一个物理CPU,通过快速地轮流执行多个进程,制造出每个进程都独占一个虚拟CPU的假象。操作系统需要为每个虚拟CPU维护一个数据结构(如进程控制块PCB),用来保存其PC、SP、通用寄存器等状态。进程之间的切换可能由多种原因触发:操作系统设置定时器中断来被动地进行调度切换;进程也可能主动放弃CPU(如等待I/O时);或者因为I/O操作完成而引发切换。
处理这种并发性要求操作系统能够监控系统中的所有活动实体,包括多个进程和各种I/O设备。其基础观点是将整个系统视为一组“虚拟机”的集合。著名的Dijkstra在设计和论证THE操作系统时,就深入探讨了这些问题。
在朴素多道程序系统中,所有虚拟CPU共享非CPU资源,如I/O设备和物理内存。这种方法常见于一些嵌入式系统、Windows 95之前的DOS/Windows系统以及早期的Macintosh系统中。
带保护的多道程序
这种方法在CPU虚拟化的基础上,进一步通过硬件和操作系统协作,实现了对内存的虚拟化和保护。
操作系统通过掌控地址翻译过程,能够禁止用户进程直接访问其他进程或操作系统内核的内存区域。这为系统带来了可靠性(一个进程崩溃不会影响整个系统)、安全性(防止恶意软件)、隐私性(保护用户数据)和公平性(保证资源公平分配)。
实现内存保护的技术有很多种,这里介绍一种经典且相对简单的方法——基址-界限寄存器。系统为每个进程分配一段连续的物理内存,并记录这段内存的起始地址(基址)和长度(界限)。当进程访问一个虚拟地址时,硬件会自动将其加上基址寄存器中的值,得到物理地址。在访问内存之前,硬件会检查这个物理地址是否落在
[基址, 基址+界限)
的范围内。如果越界,则会触发一个异常,由操作系统进行处理,从而实现了有效的隔离和保护。Prev
ICS12 并发编程
Next
OS02 抽象-线程与进程
Loading...