如图1-10所示,所有应用程序对硬件的操作尝试都必须通过操作系统。
操作系统有两个基本功能:(1)防止硬件被失控的应用程序滥用;(2)向应用程序提供简单一致的机制来控制复杂而又通常大不相同的低级硬件设备。操作系统通过几个基本的抽象概念(进程、虚拟内存和文件)来实现这两个功能。如图1-11所示,文件是对I/O设备的抽象表示,虚拟内存是对主存和磁盘I/O设备的抽象表示。进程则是对处理器、主存和I/O设备的抽象表示。
虚拟内存
虚拟内存是一个抽象概念,它为每个进程提供了一个假象,即每个进程都在独占地使用主存。每个进程看到的内存都是一致的,称为虚拟地址空间。图1-13所示的是Linux进程的虚拟地址空间(其他Unix系统的设计也与此类似)。在Liunx中,地址空间最上面的区域是保留给操作系统中的代码和数据的,这对所有进程来说都是一样。地址空间的底部区域存放用户进程定义的代码和数据。请注意,图中的地址是从下往上增大的。
每个进程看到的虚拟地址空间由大量准确定义的区构成,每个区都有专门的功能。
程序代码和数据。 对所有的进程来说,代码是从同一固定位置开始,紧接着的是和C全局变量相对应的数据位置。代码和数据区是直接按照可执行目标文件的内容初始化的,在示例中就是可执行文件hello。
堆。 代码和数据区后紧随着的是运行时堆。代码和数据区在进程一开始运行时就被指定了大小,与此不同,当调用像malloc和 free这样的C标准库函数时,堆可以在运行时动态地扩展和收缩。
共享库。大约在地址空间的中间部分是一块用来存放像C标准库和数学库这样的共享库的代码和数据的区域。
栈。 位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数调用。和堆一样,用户栈在程序执行期间可以动态地扩展和收缩。特别地,每次我们调用一个函数时,栈就会增长;从一个函数返回时,栈就会收缩。
内核虚拟内存。地址空间顶部的区域是为内核保留的,不允许应用程序读写这个区域的内容或者直接调用内核代码定义的函数。相反,它们必须调用内核来执行这些操作。
并发和并行
数字计算机的整个历史中,有两个需求是驱动进步的持续动力:一个是我们想要计算机做得更多,另一个是我们想要计算机运行得更快。当处理器能够同时做更多的事情时,这两个因素都会改进。我们用的术语并发(concurrency)是一个通用的概念,指一个同时具有多个活动的系统;而术语并行(parallelism)指的是用并发来使一个系统运行得更快。并行可以在计算机系统的多个抽象层次上运用。在此,我们按照系统层次结构中由高到低的顺序重点强调三个层次。
1.线程级并发
构建在进程这个抽象之上,我们能够设计出同时有多个程序执行的系统,这就导致了并发。使用线程,我们甚至能够在一个进程中执行多个控制流。自20世纪60年代初期出现时间共享以来,计算机系统中就开始有了对并发执行的支持。传统意义上,这种并发执行只是模拟出来的,是通过使一台计算机在它正在执行的进程间快速切换来实现的,就好像一个杂耍艺人保持多个球在空中飞舞一样。这种并发形式允许多个用户同时从事多个任务,例如,在一个窗口中开启Web浏览器,在另一窗口中运行字处理器,同时又播放音乐。在以前,即使处理器必须在多个任务间切换,大多数实际的计算也都是由一个处理器来完成的。这种配置称为单处理器系统
当构建一个由单操作系统内核控制的多处理器组成的系统时,我们就得到了一个多处理器系统。其实从哪20世纪80年代开始,在大规模的计算中就有了这种系统,但是直到最近,随着多核处理器和超线程(hyoerthreading)的出现,这种系统才变得常见。图1-16给出了这些不同处理器类型的分类。
多核处理器是将多个CPU(称为"核")集成到一个集成电路芯片上。图1-17描述的是一个典型多核处理器的组织结构,其中微处理芯片有4个CPU核,每个核都有自己的L1和L2高速缓存,其中的L1高速缓存分为两个部分--一个保存最近取到的指令,另一个存放数据。这些核共享更高层次的高速缓存,以及到主存的接口。
超线程,有时称为同时多线程(simultaneous multi-threading),是一项允许一个CPU执行多个控制流的技术。它涉及CPU某些硬件有多个备件,比如程序计数器和寄存器文件,而其他的硬件部分只有一份,比如执行浮点算数运算的单元。常规的处理器需要大概20000个时钟周期做不同线程间的切换,而超线程的处理器可以在单个周期的基础上决定要执行哪一个线程。这使得CPU能够更好地利用它的处理资源。比如,假设一个线程必须等到某些数据被装载到高速缓存中,那CPU就可以继续去执行另一个线程。举例来说,Intel Core i7处理器可以让每个核执行两个线程,所以一个4核的系统实际上可以并行地执行8个线程。
多处理器的使用可以从两方面提高系统性能。首先,它减少了在执行多个任务时模拟并发的需要。正如前面提到的,即使是只有一个用户使用的个人计算机也需要并发地执行多个活动,其次,它可以使应用程序运行时更快,因此,虽然并发原理的形成和研究已经超过50年的时间了,但是多核和超线程系统的出现才极大地激发了一种愿望,即找到书写应用程序的方法利用硬件开发线程级并行性。
2.指令级并行
在较低的抽象层次上,现代处理器可以同时执行多条指令的属性称为指令级并行。早期的微处理器,如1978年的Intel 8086,需要多个(通常是310个)时钟周期来执行一条指令。最近的处理器可以保存每个时钟周期24条指令的执行速率。其实每条指令从开始到结束需要长得多的时间,大约20个或者更多周期,但是处理器使用了非常多的聪明技巧同时处理多达100条指令。
如果处理器可以达到比一个周期一条指令更快的执行速率,就称为超标量处理器。大多数现代处理器都支持超标量操作。
3.单指令、多数据并行
在最低层次上,许多现代处理器拥有特殊的硬件,允许一条指令产生多个可以并发执行的操作,这种方式称为单指令、多数据,即SIMD并行。