《操作系统精髓与设计原理》—— 1. 计算机系统概述

前言

以前一直对操作系统感到好奇,总感觉很神秘,因此最近一段时间打算研究一下操作系统,主要参考书籍是《操作系统精髓与设计原理》,有兴趣的猿友可以一起学习,共同探讨,揭开她的神秘面纱。

操作系统在计算机中处于中间位置,它的上层是应用程序,而下层是计算机系统的硬件,具有承上启下的作用,因此为理解操作系统的功能和设计问题,需要对硬件有一个基本的了解。本章主要对计算机系统中的处理器、内存和 I/O 原理进行简要的介绍。

1. 计算机的 4 个主要组成部分

在这里插入图片描述

  • 处理器(processor): 通常指中央处理单元 CPU,主要用来控制计算机的操作,执行数据的处理功能。CPU 中有许多寄存器用来存放数据。

    CPU 和内存交换数据通常需要使用内部的两个寄存器:
    存储器地址寄存器(Memory Address Register,MAR),存放下一次读写的内存地址;
    存储器缓冲寄存器(Memory Buffer Register,MBR),用于存放将要写入内存的数据或者从内存中读取的数据;

    同理,输入/输出地址寄存器(I/O Address Register,I/O AR),确定一个特定的输入/输出设备;
    输入/输出缓冲寄存器(I/O Address Register,I/O BR),用于输入/输出模块和 CPU 交换数据;

    程序计数器(Program Counter,PC):存放将要取指令的地址;
    指令寄存器(Instruction Register,IR):存放最近一次从内存取出的指令内容。

    算术逻辑单元(Arithmetic&Logical Unit,ALU) ,是 CPU 的执行单元,是所有中央处理器的核心组成成分,是专门执行算术和逻辑运算的数字电路。

  • 内存(main memory): 内存用于存储数据和程序,由一组单元组成,这些单元由顺序编号的地址定义,每个单元包含一个二进制数,可以解释为一个指令或数据。
    在断电时,内存中的所有数据将会丢失,因此用来临时存放数据。而磁盘存储器(也叫外存或辅存)的内容在断电时不会丢失,因为内存是半导体材料制作,硬盘是磁性材料制作。

  • 输入/输出模块(I/O module): 在计算机和外部环境之间移动数据。外部环境由各种外部设备组成,如硬盘、终端等。

  • 系统总线(system bus): 为处理器、内存和 I/O模块间提供通信。按照计算机所传输的信息种类,计算机的总线可以划分为以下三种:

    数据总线: 数据总线 DB 是双向三态形式的总线,即它既可以把 CPU 的数据传送到存储器或输入输出接口等其它部件,也可以将其它部件的数据传送到 CPU。数据总线的位数是微型计算机的一个重要指标,通常与微处理的字长相一致。我们说的 32 位,64 位计算机指的就是数据总线。

    地址总线: 地址总线 AB 是专门用来传送地址的,由于地址只能从 CPU 传向外部存储器或 I/O 端口,所以地址总线总是单向三态的,这与数据总线不同。地址总线的位数决定了 CPU 可直接寻址的内存空间大小。

    控制总线: 控制总线主要用来传送控制信号和时序信号。控制总线的传送方向由具体控制信号而定,一般是双向的,控制总线的位数要根据系统的实际控制需要而定。其实数据总线和控制总线可以共用。

2. 指令的执行

处理器执行的程序是一组保存在内存中的指令组成。处理器执行一条指令的过程称为一个指令周期,一般分为两个阶段:取指阶段执行阶段。如下图:
在这里插入图片描述

2.1 取指令和执行指令

在每个指令周期开始,处理器根据 程序计数器(PC) 指向的内存地址,从内存中取一条指令存放在 指令寄存器(IR) 中,然后 PC 递增,使它指向下一条指令的内存地址,最后处理器执行 IR 中的指令,然后进入下一个指令周期,以此类推。

例如,假如有一个简化的计算机,每条指令占据内存中一个 16 位的字,假设程序计数器 PC 被设置为地址 300,处理器下一次将在地址为 300 的存储单元处取指令,在随后的指令周期中,它将从地址为 301、302、303 等的存储单元处取指令。

指令格式:
一条指令通常由两个部分组成:操作码 + 操作数
操作码:指明该指令要完成的操作的类型或性质,如取数、做加法或输出数据等
操作数:指明操作对象的内容或所在的存储单元地址

在这里插入图片描述

示例
假设一台机器有如下特征:处理器包含一个称为累加器(AC)的数据寄存器,所有指令和数据都是 16 位,使用 16 位的单元或字来组织存储器。指令格式中有 4 位是操作码,因而有 24=16 种不同的操作码,剩余的 12 位是操作数,因此可直接访问的存储器大小最大为 212=4096(4K)个字。

在这里插入图片描述
下图描述了程序的部分执行过程,把地址为 940 的存储单元中的内容与地址为 941 的存储单元的内容相加,并将结果保存到后一个单元中。这需要三条指令,可用三个取指阶段和三个执行阶段描述:
在这里插入图片描述
以下描述中的数字使用十六进制。
1)PC 中包含第一条指令的地址为 300,该指令的内容被送入 IR 中,PC 增 1。注意,处理此过程使用了 MAR 和 MBR。为简单起见,这些寄存器没有显示。
2)IR 中最初 4 位(第一个十六进制数)表示需要加载 AC,剩下的 12 位表示地址 940。
3)从地址为 301 的存储单元中取下一条指令,PC 增 1。
4)AC 中以前的内容和地址为 941 的存储单元中的内容相加,结果保存在 AC 中。
5)从地址为 302 的存储单元中取下一条指令,PC 增 1。
6)AC 中的内容被存储在地址为 941 的存储单元中。
在这个例子中,执行这个程序一共需要三个指令周期,每个指令周期都包含一个取指阶段和一个执行阶段。

3 中断

在系统编程中,中断是硬件或软件向处理器发出的信号,指示需要立即关注的事件。中断会警告处理器处于高优先级状态,要求中断处理器正在执行的当前代码。处理器通过挂起当前活动,保存其状态并执行称为 中断处理程序(或中断服务例程,ISR) 的功能处理该事件来作出响应。此中断是暂时的,在中断处理程序完成后,处理器将恢复正常活动。—— 《微软学术》

有两种类型的中断:由硬件产生的中断叫硬中断和由软件产生的中断叫软中断。

3.1 中断的起源

中断最初是用于提高处理器效率的一种手段。

在中断没有出现之前,CPU 对 I/O 采用的是轮询的方式进行服务,这使的 CPU 纠结在某一个 I/O 上,一直在等待它的响应,如果它不响应,CPU 就在原地一直的等下去,这样就导致了 CPU 的效率低下。例如,大多数 I/O 设备比处理器慢得多,假设处理器给一台打印机传送数据,在每次写操作后,处理器必须暂停保持空闲,直到打印机完成工作给处理器回应,处理器才能继续往下执行程序。如图1.5a。

图中 1、2、3为代码段,不涉及 I/O 的指令序列,WRITE 调用要执行一个 I/O 程序,此 I/O 程序是一个系统工具程序,由它执行真正的 I/O 操作。此 I/O 程序由三部分组成:

  • 标记为 4 的指令序列用于为实际的 I/O 操作做准备
  • 实际的 I/O 命令,如果不使用中断,则处理器必须检测 I/O 设备的状态,以确定 I/O 操作是否完成
  • 标记为 5 的指令序列,用于完成操作。包括设置一个表示操作成功或失败的标记

在这里插入图片描述

3.2 中断和指令周期

利用中断功能,处理器可以在 I/O 操作的过程中执行其它命令。如图1.5b 所示的控制流,和前面一样,用户程序到达系统调用 WRITE 处,涉及的 I/O 程序仅包括准备代码和真正的 I/O 命令。在这些为数不多的几条指令执行后,控制返回到用户程序。在这期间,外部设备忙于从计算机存储器接收数据并打印。这种 I/O 操作和用户程序中指令的执行是并行的。

当外部设备做好服务的准备,也就是说,当外部设备准备好从处理器接受更多的数据时,该为外部设备的 I/O 模块给处理器发送一个 中断请求 信号。这时处理器会做出响应,暂停当前的程序,转去处理服务于特定 I/O 设备的程序,这个程序称做中断处理程序,在对该设备的服务响应完成后,处理器恢复原来的执行。这样就大大的提高了 CPU 的效率。

为适应中断产生的情况,在指令周期中要增加一个 中断阶段。如下图所示。在中断阶段,处理器会检查是否有中断,如果有,处理器挂起当前正在执行的程序,并转去执行中断处理程序;如果没有,处理器继续运行,并在取指周期取下一条指令。

在这里插入图片描述

3.3 中断处理流程

下图显示了一个典型的序列,当 I/O 设备完成一次 I/O 操作时,发生下列硬件事件:
在这里插入图片描述

1)设备给处理器发出一个信号。

2)处理器响应中断前结束当前指令的执行。

3)处理器对中断进行测定,确定存在未响应的中断,并给提交中断的设备发送确认信号,确认信号允许该设备取消它的中断信号。

4)处理器需要为把控制权转移到中断程序在去做准备。首先,需要保存从中断点恢复当前程序所需的信息,要求的最少信息包括程序状态字(PSW)和保存在程序计数器中的下一条要执行指令的地址,它们被压入系统控制栈。

5)处理器把响应此中断的中断处理程序入口地址表装入程序计数器中(如果有多个中断,处理器就必须决定调用哪一个,例如根据中断优先级进行判断),一旦完成对程序计数器的装入,处理器则继续到下一个指令周期。

6)在这一点,与被中断程序相关的程序计数器和 PSW 被保存到系统栈中一样,还有一些其他信息被当作正在执行程序的状态的一部分。特别需要保存处理器寄存器的内容,因为中断处理程序可能会用到这些寄存器,因此所有的这些值和状态信息都必须保存。

7)中断处理程序开始处理中断。

8)当中断结束后,被保存的寄存器的值从栈中释放并恢复到寄存器中,如图1.11b。

9)最后的操作是从栈中恢复 PSW 和程序计数器的值。

在这里插入图片描述

3.4 多道程序设计

即使使用了中断,处理器也仍有可能未得到的有效利用,例如图1.5c 处理器在长 I/O 状态下等待,如果完成 I/O 操作的时间远远大于 I/O 调用期间用户代码的执行时间,则大部分时间处理器是空闲的。解决这个问题的办法是允许多道用户程序同时处于活跃状态下。

4. 存储器的层次结构

计算机存储器的设计目标可以归纳成三个问题:多大的容量?多快的速度?多贵的价格?

而这三者往往存在以下关系:

  • 存取时间越快,每一个位的价格越高。
  • 容量越大,每一个位的价格越低
  • 容量越大,存取速度越慢

那么如何设计出具有较大容量、较低价格且性能又好的存储器呢?

解决办法就是,不依赖于单一的存储组件或技术,而是使用 存储器的结构层次。一种典型的层次结构如下图所示,当沿着这个层次结构从上向下看时,会得到以下情况:
  a)每一个位的价格递减
  b)容量递增
  c)存取时间递增
  d)处理器访问存储器的频率递减
  因此,容量较大,价格较便宜的慢速存储器是容量较小,价格较贵的快速存储器的后备。这种存储器的层次结构能够成功的关键在于低层次访问频率递减。(利用局部性原理)
在这里插入图片描述
内存通常是高速的容量较小的高速缓存的扩展。高速缓存通常对处理器不可见。高速缓存用于在内存和处理器的寄存器之间移动数据,以提高数据访问的性能。

外部的、非易失性的存储器也称为二级存储器或辅助存储器,它们用于存储程序和数据文件。硬盘还用作内存的扩展,即虚拟存储器。

在软件中还可以有效地增加额外的存储层次。例如,一部分内存可以作为缓冲区(buffer),用于临时保存从磁盘中读出的数据,这种技术称为磁盘高速缓存。

5. 高速缓存

5.1 动机

在全部指令周期中,处理器取指令时至少访问一次存储器,而且通常还要多次访问存储器用于取操作数或保存结果。处理器执行指令的速度显然受限于存储周期的限制。

由于处理器和内存的速度不匹配造成严重问题,解决办法就是内存的构造技术采用和处理器中的寄存器相同的构造技术,但这样做成本太高,因此采用另一种办法,利用 利用局部性原理,在处理器和内存之间加一个容量小而速度快的存储器,即高速缓存。

局部性原理 指的是位于被访问字附近的数据在近期被访问到的概率比较大。

5.2 高速缓存原理

高速缓存试图使访问速度接近现有最快的存储器,同时保持价格便宜的大存储容量(以较为便宜的半导体存储器技术实现)。

在这里插入图片描述
如图1.16,高度缓存包含一部分内存数据的副本,当处理器要读取内存中的一个字节或字时,会先看看高速缓存中是否有该字节或字,如果有,该字或字节从高速缓存传递给处理器;如果没有,则由固定数目的字节组成的一块内存数据先被读入高速缓存,然后该字节或字从高速缓存传递给处理器。

在这里插入图片描述
图1.17 描述了高速缓存/内存的结构,内存由 2n 个可寻址的字组成,每个字有一个唯一的地址。

假设每个块包含 K 个字,则一共有 M=2n/K 个块。高速缓存有 C 个存储槽(slot),每个槽有 K 个字,槽的数目远小于块的数目(C << M)。内存中块的某些子集驻留在高速缓存的槽中,如果读存储器中某一个块的某一个字,而这个块又不在槽中,则这个块被转移到一个槽中。由于块的数目比槽多,一个槽不可能永久对应于一个块。因此,每个槽中有一个标签,用以标识当前存储的是哪一个块。

5.3 高速缓存设计

在进行高速缓存设计时,必须解决以下问题:高速缓存的大小、块大小、映射函数、替换算法、写策略。

  • 高速缓存的大小:适当小的高速缓存可以对性能产生很大影响。

  • 块大小:块是高速缓存与内存交换数据的基本单位。当块大小从很小增长到很大时,由于局部性原理,命中率首先会增加。命中指的是在高速缓存中找到了存取的字。但是,但块变得更大时,新近取到的数据被用到的可能性开始小于那些必须被移出高速缓存的数据再用到的可能性,这时命中率反而降低。

  • 映射函数:当一个新块被读入高速缓存中时,映射函数确定这个块存放的位置。

    映射函数需要考虑两方面的约束:一是,当读入一个块时,另一个块可能会被替换出高速缓存。替换方法应尽量减少替换出的块在不久的将来还会用到的可能性。映射函数设计的越灵活就有更大余地设计出可以增大命中率的替换算法。二是函数越灵活,则完成搜索以确定某个指定的块是否在高速缓存中的功能所需的逻辑电路就越复杂。

  • 替换算法:替换算法应选择替换不久的将来被访问的可能性最小的块。合理且有效的策略是替换高速缓存中长时间未被访问的块,这个策略称为最近最少使用(Least-Recently-Used,LRU)算法。

  • 写策略:如果高速缓存中某个块的内容被修改,在将它从高速缓存中替换出之前,则需要把它写回内存。写策略规定何时发生存储器写操作。一种极端情况是每当块被更新就发生写操作;而另一种极端情况是只有当它被替换出高速缓存中时,才会发生写操作。后一种策略减少了写的次数,但是使内存处于一种过时的状态,这会妨碍多处理器操作以及 I/O 模块的直接内存存取(DMA)。

6. I/O操作的三种技术

6.1 可编程 I/O

当处理器执行程序并遇到一个 I/O 指令时,它通过给 I/O 模块发送命令来执行这个指令。

使用可编程 I/O 操作时,当处理器遇到一条 I/O 指令时,处理器给 I/O 模块发送命令来执行这条指令,I/O 模块执行请求的动作并设置 I/O 状态寄存器中相应的位,它并不进一步通知处理器,尤其是不中断处理器,因此处理器必须定期检查 I/O 模块的状态,以确定是否完成 I/O 操作。

例如下图1.19a:将外部设备(如硬盘)的一块数据读进内存,每次读一个字(例如 16 位)的数据。每次读取一个字后,处理器必须检查 I/O 模块的状态,直到确定该字已经在 I/O 模块的寄存器中。

缺点:处理器总是处于没有用的繁忙中。
在这里插入图片描述

6.2 中断驱动 I/O

而中断驱动 I/O 解决了上述的缺点,处理器给 I/O 模块发送命令后,就可以干其他活了,不用在周期性的检查 I/O 模块的状态。当 I/O 模块准备好数据可以和处理器交换时,它将给处理器发送一个中断信号,打断处理器执行的程序并请求服务。

首先从 I/O 模块的角度来看:I/O 模块收到处理器发送的一个 READ 命令,然后从外围设备中读取一个字,一旦数据被读进该模块的数据寄存器,模块就会通过控制线给处理器发送一个中断信号,然后等待处理器请求该数据,当收到处理器的请求后,模块把数据放到数据总线上,然后准备下一次的 I/O 操作。

从处理器的角度来看:处理器给 I/O 模块发送 READ 命令,然后转去做其他事情,直到收到该 I/O 模块的中断信号后,处理器从 I/O 模块中读取数据并保存在内存中。(注意:处理器从一个程序切换到另一个程序时,必须保存当前执行程序的上下文,以备在之后恢复该程序时使用)

缺点:数据的每个字不论是从 I/O 模块到内存还是从内存到 I/O 模块,都必须经过处理器的中转,这导致中断驱动 I/O 仍然会花费处理器很多时间。解决办法就是 DMA。

6.3 直接内存存取(DMA)

直接内存存取就是数据不在经过处理器,而是 I/O 直接与内存进行交互数据。具体工作方式如下:当处理器读或写一块数据时,它给 DMA 模块产生一条命令,发送以下信息:

  • 是否请求一次读或写

  • 涉及的 I/O 设备的地址

  • 开始读或写的内存单元

  • 需要读或写的字数

    之后处理器继续其它工作。处理器把这个操作委托给 DMA 模块,由该模块负责数据的传输。当传送完成后,DMA 模块发一个中断信号给处理器。因此只有在开始传送和传送结束时处理器才会参与。(如上图1.19c)

7. 总结

本文主要对计算机系统结构进行了简要的介绍,包括处理器、内存和 I/O 原理以及指令的执行过程和中断概念等。这将为后续的操作系统学习做一个铺垫。

发布了42 篇原创文章 · 获赞 11 · 访问量 3831

猜你喜欢

转载自blog.csdn.net/weixin_44584387/article/details/101459144