操作系统,什么是"操作"呢?在早期,当你打电话时,他们实际上必须把你插到正确的连接上,让电线连接起来;然后是早期的计算机,需要计算机操作员,他们基本上是长时间坐在这些大机器前的人,确保它运行正常,然后就会操作系统了。这个“操作”系统就是要保证磁盘运行正确,网络运行正常,或者显卡等等都运行正常。
那是什么构成了一个"系统"呢?一个系统是由许多相互关联的部分组成的,一般来说,他们协作实现的要比各部分本身的功能大得多,每个相互关联的部分都可能与其他部分相互作用,当然,复杂度也变成了至少是 n 的平方。我们必须想出 api 和其他聪明的技术来避免 n 平方的复杂度,因为事情已经足够复杂了。对于这些 api 的使用以及理解就是系统编程,系统编程是这门课很重要的一部分,在这门课上你会接触很多的系统编程。
对于硬件/软件接口:你有一个处理器,在处理器里有寄存器,这些寄存器指向内存的一部分,这样程序就能运行了;可能处理器里面还有缓存,但它并没有很大,缓存的作用就是让内存和磁盘这些大容量但是访问较慢的看上去可以像寄存器访问一样快,通过一定的缓存设计。在虚拟内存的设计中,还有页表和翻译后备缓冲可以帮助我们。当然还有各种存储,例如内存还有磁盘。还有有各种各样的设备,比如网络、显示器和输入等等。这些纷杂的硬件都有自己的复杂的硬件接口,但是操作系统将这些复杂的硬件接口统一抽象成软件接口,供应用程序使用。比如抽象出了处理器的计算元素,把一堆存储设备,比如磁盘,u盘和云存储,变成一个单一的抽象即文件系统,这样应用就可以很容易地使用而不用关心其中的内容(每一位数据)实际存储的位置。这些也是这门课的核心内容。
操作系统充当的第一个角色,就是魔术师这样一个角色。它会提供简单明了的物理资源抽象,它会以一种方式让你至少暂时认为你拥有无限的内存,你有一台完全专用于你的机器或一个处理器,它有更高级的对象,如文件、用户和消息。这样会让你写代码更容易写,例如如果没有文件这个对象,那么你操作的就是磁盘上的一堆块,而文件是磁盘上一堆单独的块的抽象,它们以某种方式与 inodes(索引节点)放在一起,形成一个文件。
这是一台普通的物理机,它有内存,有I/O,可能还有存储和网络。在它上面我们会放一个操作系统,我们现在正在学习这个。操作系统将处理器资源抽象成一个非常简洁的东西,即线程(Thread);我们将会有地址空间(Address Space),我们将会学习的不是在 DRAM 中分散在各处的一堆内存字节,而是一个干净的地址空间抽象,这将使我们能够把内存当作完全属于我们的,即使有多个程序在运行。我们将会有文件(File),而不是一堆单独的磁盘上的块。我们将会有套接字(Socket),而不是直接操作网卡。在这些线程,地址空间,文件和套接字之上,将会有进程(Process)抽象,这个进程抽象将给我们一个由操作系统提供的受限权限的执行环境,在里面跑我们编译好的程序。为了给你一个干净的环境来进行编程使用这些抽象资源,会有系统库(System Libraries)
为什么抽象这些中间层是必要的:如果你试图去掉所有中间层直接操作底层(有时在非常特殊的环境中会这样做),你会发现特别麻烦,因为不同的底层硬件接口是不一样。这些抽象虽然对于性能有一点点损耗,但是带来的是统一接口统一代码的便利性。
系统库被链接到你的程序中,然后由编译器运行,然后被转换成在程序中运行的机器码,然后在进程环境中执行它们。
在进程中有什么:
- 一个进程有一个地址空间,也就是一块受保护的内存
- 它有一个或多个线程,访问上面那些地址空间
- 其他的系统状态(system state):包括打开的文件和套接字等等
这里有一个例子,是 MAC 系统的例子,你可以查看进程监视器或任务管理器。类似于或者你在 Linux 机器上面执行 ps -aux
。你会发现,在你的机器上,有很多很多的进程在运行。大多数都在 sleep,但他们会在某一时刻唤醒,执行一些任务。
这是操作系统对于多个进程的管理,每个进程都有自己的一组线程、地址空间、文件和套接字,它们可能会运行一个带有自己链接库的程序,并且这些进程实际上互相保护自己不受其他进程影响的。操作系统将底层的硬件接口转换成应用程序接口,每个程序都有自己的进程,进程是一个受保护的运行环境。
操作系统的另一个角色即裁判,管理进程之间的资源的隔离以及共享。
我们接下来看一个简单的例子,假设这个例子中只有一个处理器:
假设我们有编译好的程序 1 (棕色)和程序 2(绿色),我们只有一个处理器(Processor,一个核心 core,我们目前认为一个处理器只有一个核心,在后续的课程中可能会有多核的情况,这里先不考虑),那么操作系统怎么让这两个程序看起来同时在运行呢?首先每个程序都有自己的进程,每个进程都有自己的全局唯一进程描述符(Process Identifier)。在内存中,进程 1 有自己的内存空间(棕色),进程 2 也有自己的内存空间(绿色),同时,内存中还有灰色的代表操作系统使用的一些内存空间。然后,处理器里面做的就是不断地进程切换,先从一个开始,例如进程 1,这时候处理器执行的就是程序 1 的代码,处理器中的寄存区保存的是程序 1 需要的内容,访问的就是进程 1 的内存空间。