MIT操作系统神课 - 精读第二章
第二章 操作系统结构
想象你的计算机上跑着机器学习,但是你又想听歌,但是你的计算机只有一个CPU,如果把所有的CPU资源都拿去跑机器学习的话,你必须等程序跑完之后才能听歌。但是现实是,你可以在机器学习程序运行的时候放着自己喜欢的歌,甚至还可以打开微信聊天。这就是操作系统一个很重要的功能,那就是操作系统需要支持多个进程同时运行,例如在第一章中提到的,我们可以用fork
创建子进程,然后父进程和子进程会在相同的内存空间上同时运行。但是父进程和子进程的运行顺序是不确定的,因为这取决于调度器的决策,所以操作系统还必须要做好调度工作,让每个进程都能够利用有限的CPU资源来运行自己的代码,即对资源进行复用。操作系统另一个很重要的作用是使进程与进程之间相互隔离,因为需要防止一个进程在运行出现的错误影响到其他进程的运行,又或者进程会访问到内核资源,对内核进行破坏。但是进程之间又不应该是绝对的隔离,因为有时候我们还需要让进程之间进行通信,或者共享数据。
总的来说,一个操作系统满足一下三个要求:
- 能够对有限资源进行合理的分配和复用;
- 能够使进程与进程之间保持各自运行的独立性,起到隔离进程的作用;
- 能够使进程之间进行交流和通信,必要时进行数据的共享和传输。
本章将主要介绍实现上述三个要求的办法,其实有很多不同的实现方式,因为不同的操作系统会有不同的操作系统内核架构。一些功能较为简单的操作系统,会将应用程序和操作系统放在同一个地址空间中,应用程序可以直接通过函数调用操作系统提供的服务。但是这样做法的缺点显而易见,如果操作系统的某个模块出现问题,应用程序也会崩溃;同时由于程序有了很大的自由度,恶意的程序可能对系统造成危害。所以会本章还会主要介绍几种常见的内核组织架构,其中包括宏内核(monolithic kernel)
和微内核(Microkernel)
架构.
本实验的xv6运行在一个多核的RISC-V微处理器上,RISC-V是一个64位的CPU,所以在编写xv6时,一般的数据类型long和pointers都是64位的,而int是32位的。
对物理资源进行抽象
设计操作系统时,为了保证硬件资源的充分利用,我们需要让每个应用程序周期地放弃资源,然后好让其他程序运行。这里体现了操作系统的公平性,以及操作系统应该具有调度的功能。这样的分时系统在每个程序运行正常的情况下能够很好地工作,但是每个程序难免出现运行错误或者不愿意空出资源的情况。所以为了让进程之间能够更独立地运行,我们可以禁止应用去接触敏感的硬件资源,而是将资源的利用抽象进一个个服务里。就像上一章所提到的,我们通过系统调用open, read, write, close来对内存进行读写操作,而不是对物理内存直接进行读写。所以文件系统就是对物理的硬件资源一个很好的抽象,当CPU在每个进程之间进行切换时,操作系统要做的只需要将每个进程运行停止时必要的寄存器信息保存下来,这样即使某个进程出现问题,也能够切换到其他进程,然后再返回。
文件系统是对物理资源进行的抽