第2章 操作系统概述
学习内容:
- 操作系统的主要功能
- 早期批处理系统到现代复杂的系统:操作系统的演化
- 2.3节的操作系统研究的每一项主要成果,给出简要的说明
- 有助于现代操作系统开发的主要设计领域
- 定义并讨论虚拟机的虚拟化
- 多处理器和多核计算机带来的操作系统设计问题
- windows7的基本结构
- 传统UNIX系统的基本要求
- 现代UNIX系统的新特性
- 掌握Linux及其与UNIX的关联
2.1 操作系统的目标和功能
操作系统是控制应用程序执行的程序,并充当应用程序和计算机硬件之间的接口。有三个目标:
- 方便:操作系统使计算机更易于使用。
- 有效:操作系统允许以更有效的方式使用计算机系统资源。
- 扩展能力:在构造操作系统时,应该允许在不妨碍服务的前提下有效地开发、测试和引进新的系统功能。
2.1.1 作为用户/计算机接口的操作系统
为用户提供应用的硬件和软件可以看做是一种层次结构,如图2.1 所示。应用程序的用户并不关心计算机的硬件细节。因此,终端用户把计算机系统看做是一组应用程序。如果需要用一组完全负责控制计算机硬件的机器指令开发应用程序,将会是一件非常复杂的任务。为简化这个任务,需要提供一些系统程序,其中一部分称做实用工具,它们实现了在创建程序、管理文件和控制I/O 设备中经常使用的功能。程序员在开发应用程序时将使用这些功能提供的接口;在应用程序运行时,将调用这些实用工具以实现特定的功能。最重要的系统程序是操作系统,操作系统为程序员屏蔽了硬件细节,并为程序员使用系统提供方便的接口。它可以作为中介,使程序员和应用程序更容易地访问和使用这些功能和服务。
操作系统通常提供了以下几个方面的服务:
- 程序开发:操作系统提供各种各样的工具和服务,如编辑器和调试器,用于帮助程序员开发程序。通常,这些服务以实用工具程序的形式出现,严格来说并不属于操作系统核心的一部分;它们由操作系统提供,称做应用程序开发工具。
- 程序运行:运行一个程序需要很多步骤,包括必须把指令和数据载入到内存、初始化I/O设备和文件、准备其他一些资源。操作系统为用户处理这些调度问题。
- I/O 设备访问:每个I/O 设备的操作都需要特有的指令集或控制信号,操作系统隐藏这些细节并提供了统一的接口,因此程序员可以使用简单的读和写操作访问这些设备
- 文件访问控制:对操作系统而言,关于文件的控制不仅必须详细了解I/O 设备(磁盘驱动器、磁带驱动器)的特性,而且必须详细了解存储介质中文件数据的结构。此外,对有多个用户的系统,操作系统还可以提供保护机制来控制对文件的访问。
- 系统访问:对于共享或公共系统,操作系统控制对整个系统的访问以及对某个特殊系统资源的访问。访问功能模块必须提供对资源和数据的保护,以避免未授权用户的访问,还必须解决资源竞争时的冲突问题。;
- 错误检测和响应:计算机系统运行时可能发生各种各样的错误,包括内部和外部硬件错误,如存储器错误、设备失效或故障,以及各种软件错误,如算术溢出等。对每种情况,操作系统都必须提供响应以清除错误条件,使其对正在运行的应用程序影响最小。响应可以是终止引起错误的程序、重试操作或简单地给应用程序报告错误。
- 记账:一个好的操作系统可以收集对各种资源使用的统计信息,监控诸如响应时间之类的性能参数。对多用户系统,这个信息还可用于记账。
图2.1也指明了典型计算机系统中的三种重要的接口:
- 指令系统体系结构(ISA):定义了计算机遵循的机器语言指令系统,该接口是硬件与软件的分界线。
-
- 应用程序和实用程序都可以直接访问ISA,这些程序使用指令系统的一个子集(用户级ISA);
- 操作系统使用其他一些操作系统资源的机器语言指令(系统级ISA)。
- 应用程序二进制接口(ABI):这些接口定义了程序间二进制可移植性的标准。ABI定义了操作系统的系统调用接口,以及在系统中通过ISA能使用的硬件资源和服务。
- 应用程序编程接口(API):API允许应用程序访问系统的硬件资源和服务。这些服务由用户级ISA和高级语言(HLL)库调用来提供。使用API能使应用软件更容易通过重新编译移植到其他具有相同API的系统中。
2.1.2 作为资源管理器的操作系统
一台计算机就是一组资源,这些资源用于对数据的移动、存储和处理,以及对这些功能的控制。而操作系统负责管理这些资源。
那么是否可以说是操作系统在控制数据的移动、存储和处理呢?从某个角度来看,答案是肯定的:通过管理计算机资源,操作系统控制计算机的基本功能,但是这个控制是通过一种不寻常的方式来实施的。通常,我们把控制机制想象成在被控制对象之外或者至少与被控制对象有一些差别和距离(例如,住宅供热系统是由自动调温器控制的,它完全不同于热产生和热发送装置)。但是,操作系统却不是这种情况,作为控制机制,它有两方面不同之处:
- 操作系统与普通的计算机软件作用相同,它也是由处理器执行的一段程序或一组程序。
- 操作系统经常会释放控制,而且必须依赖处理器才能恢复控制。
操作系统实际上不过是一组计算机程序,与其他计算机程序类似,它们都给处理器提供指令,主要区别在于程序的意图。操作系统控制处理器使用其他系统资源,并控制其他程序的执行时机。但是,处理器为了做任何一件这类事情,都必须停止执行操作系统程序,而去执行其他程序。因此,这时操作系统释放对处理器的控制,让处理器去做其他一些有用的工作,然后用足够长的时间恢复控制权,让处理器准备好做下一项工作。随着本章内容的深入,读者将逐渐明白所有这些机制。
图2.2 显示了由操作系统管理的主要资源。操作系统中有一部分在内存中,其中包括内核程序和当前正在使用的其他操作系统程序,内核程序包含操作系统中最常使用的功能。内存的其余部分包含用户程序和数据,它的分配由操作系统和处理器中的存储管理硬件联合控制。操作系统决定在程序运行过程中何时使用I/O 设备,并控制文件的访问和使用。处理器自身也是一个资源,操作系统必须决定在运行一个特定的用户程序时,可以分配多少处理器时间,在多处理器系统中,这个决定要传到所有的处理器。
2.1.3 操作系统的易扩展性
一个重要的操作系统应该能够不断发展,其原因如下:
- 硬件升级和新型硬件的出现:如早期运行UNIX 和Macintosh 的处理器没有“分页”的硬件,因此这两个操作系统也没有使用分页机制,而较新的版本经过修改,具备了分页功能。
- 新的服务:为适应用户的要求或满足系统管理员的需要,需要扩展操作系统以提供新的服务。例如,如果发现用现有的工具很难保持较好的性能,操作系统就必须增加新的度量和控制工具。
- 纠正错误:任何一个操作系统都有错误,随着时间的推移这些错误逐渐被发现并会引入相应的补丁程序。当然,补丁本身也可能会引入新的错误。
在构造系统时应该采用模块化的结构,清楚地定义模块间的接口,并备有说明文档。对于像现代操作系统这样的大型程序,简单的模块化是不够的,也就是说,不能只是简单地把程序划分为模块,还需要做更多的工作。在本章的后续部分将继续讨论这个问题。
2.2 操作系统的发展
了解这些年来操作系统的发展历史。
2.2.1 串行处理
早期,程序员都是直接与计算机硬件打交道的,因为当时还没有操作系统。这些机器都是在一个控制台上运行的,控制台包括显示灯、触发器、某种类型的输入设备和打印机。用机器代码编写的程序通过输入设备(如卡片阅读机)载入计算机。如果一个错误使得程序停止,错误原因由显示灯指示。如果程序正常完成,输出结果将出现在打印机中。
早期系统引出两个主要问题:
- 调度:大多数装置都使用一个硬拷贝的登记表预订机器时间。通常,一个用户可以以半小时为单位登记一段时间。有可能用户登记了1 小时,而只用了45 分钟就完成了工作,在剩下的时间中计算机只能闲置,这时就会导致浪费。另一方面,如果用户遇到一个问题,没有在分配的时间内完成工作,在解决这个问题之前就会被强制停止。
- 准备时间:一个程序称做作业,它可能包括往内存中加载编译器和高级语言程序(源程序),保存编译好的程序(目标程序),然后加载目标程序和公用函数并链接在一起。每一步都可能包括安装或拆卸磁带,或者准备卡片组。如果在此期间发生了错误,用户只能全部重新开始。需要大量时间。
这种操作模式称做串行处理,反映了用户必须顺序访问计算机的事实。后来,为使串行处理更加有效,开发了各种各样的系统软件工具,其中包括公用函数库、链接器、加载器、调试器和I/O 驱动程序,它们作为公用软件,对所有的用户来说都是可用的。
2.2.2 简单批处理系统
早期计算机由于调度和准备而浪费时间是难以接受的,因此最大限度地利用处理器是非常重要的。
为提高利用率,人们有了开发批处理操作系统的想法。简单批处理方案的中心思想是使用一个称做监控程序的软件。通过使用这类操作系统,用户不再直接访问机器,相反,用户把卡片或磁带中的作业提交给计算机操作员,由他把这些作业按顺序组织成一批,并将整个批作业放在输入设备上,供监控程序使用。每个程序完成处理后返回到监控程序,同时,监控程序自动加载下一个程序。可以从以下两个角度进行分析:监控程序角度和处理器角度。
- 监控程序角度:监控程序控制事件的顺序。为做到这一点,大部分监控程序必须总是处于内存中并且可以执行(见图2.3),这部分称做常驻监控程序(resident monitor)。其他部分包括一些实用程序和公用函数,它们作为用户程序的子程序,在需要用到它们的作业开始执行时被载入。监控程序每次从输入设备(通常是卡片阅读机或磁带驱动器)中读取一个作业。读入后,当前作业被放置在用户程序区域,并且把控制权交给这个作业。当作业完成后,它将控制权返回给监控程序,监控程序立即读取下一个作业。每个作业的结果被发送到输出设备(如打印机),交付给用户。
- 处理器角度:从某个角度看,处理器执行内存中存储的监控程序中的指令,这些指令读入下一个作业并存储到内存中的另一个部分。一旦已经读入一个作业,处理器将会遇到监控程序中的分支指令,分支指令指导处理器在用户程序的开始处继续执行。处理器继而执行用户程序中的指令,直到遇到一个结束指令或错误条件。不论哪种情况都将导致处理器从监控程序中取下一条指令。
- 因此,“控制权交给作业”仅仅意味着处理器当前取和执行的都是用户程序中的指令,
- 而“控制权返回给监控程序”的意思是处理器当前从监控程序中取指令并执行指令。
图2.3 常驻监控程序的内存布局 |
监控程序完成调度功能:
- 一批作业排队等候,处理器尽可能迅速地执行作业,没有任何空闲时间。
- 监控程序还改善了作业的准备时间,每个作业中的指令均以一种作业控制语言(Job ControlLanguage,JCL)的基本形式给出。这是一种特殊类型的程序设计语言,用于为监控程序提供指令。举一个简单的例子,用户提交一个用FORTRAN 语言编写的程序以及程序需要用到的一些数据。除了FORTRAN 指令和数据行,作业中还包括作业控制指令,这些指令以“$”符号打头。作业的整体格式如下所示:
为执行这个作业:
- 监控程序读$FTN 行,从海量存储器(通常为磁带)中载入合适的语言编译器。
- 编译器将用户程序翻译成目标代码,并保存在内存或海量存储器中。如果保存在内存中,则操作称做“编译、加载和运行”。如果保存在磁带中,就需要$LOAD 指令。
- 编译操作之后监控程序重新获得控制权,此时监控程序读$LOAD 指令,启动一个加载器,并将控制权转移给它,加载器将目标程序载入内存(在编译器所占的位置中)。
在这种方式中,有一大段内存可以由不同的子系统共享,但是每次只能运行一个子系统。
在用户程序的执行过程中,任何输入指令都会读入一行数据。用户程序中的输入指令导致调用一个输入例程,输入例程是操作系统的一部分,它检查输入以确保程序并不是意外读入一个JCL 行。如果是这样,就会发生错误,控制权转移给监控程序。用户作业完成后,监控程序扫描输入行,直到遇到下一条JCL 指令。因此,不管程序中的数据行太多或太少,系统都受保护。
可以看出,监控程序或者说批处理操作系统,只是一个简单的计算机程序。它依赖于处理器可以从内存的不同部分取指令的能力,以交替地获取或释放控制权。此外,还考虑到了其他硬件功能:
- 内存保护:当用户程序正在运行时,不能改变包含监控程序的内存区域。如果试图这样做,处理器硬件将发现错误,并将控制转移给监控程序,监控程序取消这个作业,输出错误信息,并载入下一个作业。
- 定时器:定时器用于防止一个作业独占系统。在每个作业开始时,设置定时器,如果定时器时间到,用户程序被停止,控制权返回给监控程序。
- 特权指令:某些机器指令设计成特权指令,只能由监控程序执行。如果处理器在运行一个用户程序时遇到这类指令,则会发生错误,并将控制权转移给监控程序。I/O 指令属于特权指令,因此监控程序可以控制所有I/O 设备,此外还可以避免用户程序意外地读到下一个作业中的作业控制指令。如果用户程序希望执行I/O,它必须请求监控程序为自己执行这个操作。
- 中断:早期的计算机模型并没有中断能力。这个特征使得操作系统在让用户程序放弃控制权或从用户程序获得控制权时具有更大的灵活性。
内存保护和特权指令引入了操作模式的概念。用户程序执行在用户态,在这个模式下,有些内存区域是受到保护的,特权指令也不允许执行。监控程序运行在系统态,也可以称为内核态,在这个模式下,可以执行特权指令,而且受保护的内存区域也是可以访问的。
对批处理操作系统来说,用户程序和监控程序交替执行。这样做存在两方面的缺点:一部分内存交付给监控程序;监控程序消耗了一部分机器时间。所有这些都构成了系统开销,尽管存在系统开销,但是简单的批处理系统还是提高了计算机的利用率。
2.2.3 多道程序设计批处理系统
即便对由简单批处理操作系统提供的自动作业序列,处理器仍然经常是空闲的。问题在于I/O 设备相对于处理器速度太慢。图2.4 详细列出了一个有代表性的计算过程,这个计算过程所涉及的程序用于处理一个记录文件,并且平均每秒处理100条指令。在这个例子中,计算机96%的时间都是用于等待I/O设备完成文件数据传送。
图2.4 系统利用率实例 |
图2.5a 显示了这种只有一个单独程序的情况,称做单道程序设计。处理器花费一定的运行时间进行计算,直到遇到一个I/O 指令,这时它必须等到这个I/O 指令结束后才能继续进行。
这种低效率是可以避免的。内存空间可以保存操作系统(常驻监控程序)和一个用户程序。假设内存空间容得下操作系统和两个用户程序,那么当一个作业需要等待I/O 时,处理器可以切换到另一个可能并不在等待I/O 的作业(见图2.5b)。进一步还可以扩展存储器以保存三个、四个或更多的程序,并且在它们之间进行切换(见图2.5c)。这种处理称做多道程序设计(multiprogramming)或多任务处理(multitasking),它是现代操作系统的主要方案。(点击查看大图)图2.5 多道程序设计实例 |
举例来说,一台计算机,它有250M 字节的可用存储器(没有被操作系统使用)、磁盘、终端和打印机,同时提交执行三个程序,它们的属性在表2.1 中列出。假设JOB2 和JOB3 对处理器只有最低的要求,JOB3 还要求连续使用磁盘和打印机。对于简单的批处理环境,这些作业将顺序执行,30 分钟后才完成。表2.2 中的单道程序设计列出了平均资源利用率、吞吐量和响应时间,图2.6a 显示了各个设备的利用率。
假设作业在多道程序操作系统下并行运行。由于作业间几乎没有资源竞争,所有这三个作业都可以在计算机中同时存在其他作业的情况下,在几乎最小的时间内运行(假设JOB2 和JOB3 均分配到了足够的处理器时间,以保证它们的输入和输出操作处于活动状态),所有这三个作业将在15 分钟内完成。由图2.6b 中的直方图可获得表2.2 中多道程序设计中的那一列数据,从中可以看出性能的提高是很明显的。
表2.1 示例程序执行属性
表2.2 多道程序设计中的资源利用结果
针对多道程序操作系统:
- 对准备运行的多个作业,它们必须保留在内存中,这就需要内存管理。
- 此外,如果多个作业都准备运行,处理器必须决定运行哪一个,这需要某种调度算法。
这些概念将在本章后面部分详细讲述。
(点击查看大图)图2.6 利用率直方图 |
2.2.4 分时系统
对许多作业来说,需要提供一种模式,以使用户可以直接与计算机交互。
正如多道程序设计允许处理器同时处理多个批作业一样,它还可以用于处理多个交互作业。后一种情况,由于多个用户分享处理器时间,因而该技术称做分时。
在分时系统中,多个用户可以通过终端同时访问系统,由操作系统控制每个用户程序以很短的时间为单位交替执行。因此,如果有n 个用户同时请求服务,若不计操作系统开销,每个用户平均只能得到计算机有效速度的1/n。但是由于人的反应时间相对比较慢,所以一个设计良好的系统,其响应时间应该可以接近于专用计算机。批处理和分时都使用了多道程序设计,其主要差别如下所示。
早期,系统运行在一台内存为32 000 个36 位字的机器上,常驻监控程序占用了5000 个。当控制权被分配给一个交互用户时,该用户的程序和数据被载入到内存剩余的27 000 个字的空间中。程序通常在第5000 个字单元处开始被载入,这简化了监控程序和内存管理。系统时钟以大约每0.2 秒一个的速度产生中断,在每个时钟中断处,操作系统恢复控制权,并将处理器分配给另一位用户。这项技术称为时间片技术。为便于恢复,在新的用户程序和数据被读入之前,老的用户程序和数据被写出到磁盘。随后,当获得下一次机会时,老的用户程序代码和数据被恢复到内存中。
为减小磁盘开销,只有当新来的程序需要重写用户存储空间时,用户存储空间才被写出。这个原理如图2.7 所示。假设有4 个交互用户,其存储器需求如下:
JOB1:15 000
JOB2:20 000
JOB3:5000
JOB4:10 000
- 监控程序载入JOB1 并把控制权转交给它,如图2.7a 所示。
- 稍后,监控程序决定把控制权转交给JOB2,由于JOB2 比JOB1 需要更多的存储空间,JOB1 必须先被写出,然后载入JOB2,如图2.7b 所示。
- 接下来,JOB3 被载入并运行,但是由于JOB3 比JOB2 小,JOB2 的一部分仍然留在存储器中,以减少写磁盘的时间,如图2.7c 所示。
- 稍后,监控程序决定把控制交回JOB1,当JOB1 载入存储器时,JOB2 的另外一部分将被写出,如图2.7d 所示。
- 当载入JOB4 时,JOB1的一部分和JOB2 的一部分仍留在存储器中,如图2.7e 所示。
- 此时,如果JOB1 或JOB2 被激活,则只需要载入一部分。在这个例子中是JOB2 接着运行,这就要求JOB4 和JOB1 留在存储器中的那一部分被写出,然后读入JOB2 的其余部分,如图2.7f 所示。
(点击查看大图)图2.7 CTSS 操作 |
与当今的分时系统相比,CTSS 是一种原始的方法,但它可以工作。它非常简单,从而使监控程序最小。由于一个作业经常被载入到存储器中相同的单元,因而在载入时不需要重定位技术(在后面讲述)。这个技术仅仅写出必须的内容,可以减少磁盘的活动。在7094 上运行时,CTSS最多可支持32 个用户。
分时和多道程序设计引发了操作系统中的许多新问题。如果内存中有多个作业,必须保护它们不相互干扰,例如不会修改其他作业的数据。有多个交互用户时,必须对文件系统进行保护,只有授权用户才可以访问某个特定的文件,还必须处理资源(如打印机和海量存储器)竞争问题。在本书中会经常遇到这样或那样的问题以及可能的解决方法。
2.3 主要的成就
操作系统开发中的5 个重要的理论进展:
- 进程
- 内存管理
- 信息保护和安全
- 调度和资源管理
- 系统结构。
2.3.1 进程
进程比作业更通用一些。存在很多关于进程的定义,如下:
- 一个正在执行的程序。
- 计算机中正在运行的程序的一个实例。
- 可以分配给处理器并由处理器执行的一个实体。
- 由单一的顺序的执行线程、一个当前状态和一组相关的系统资源所描述的活动单元。后面将会对这个概念进行更清晰的阐述。
计算机系统的发展有三条主线:多道程序批处理操作、分时和实时事务系统,它们在时间安排和同步中所产生的问题推动了进程概念的发展。
- 多道程序设计:为了让处理器和I/O 设备(包括存储设备)同时保持忙状态,以实现最大效率。其关键机制是:在响应表示I/O 事务结束的信号时,操作系统将对内存中驻留的不同程序进行处理器切换。
- 分时:为了及时响应单个用户的要求,但是由于成本原因,又要可以同时支持多个用户。由于用户反应时间相对比较慢,这两个目标是可以同时实现的。当然,在这个计算中,还必须考虑操作系统的开销因素。
- 实时事务处理系统:很多用户都在对数据库进行查询或修改,例如航空公司的预订系统。事务处理系统和分时系统的主要差别在于前者局限于一个或几个应用,而分时系统的用户可以从事程序开发、作业执行以及使用各种各样的应用程序。对于这两种情况,系统响应时间都是最重要的。
在开发早期的多道程序和多用户交互系统时使用的主要工具是中断。一个已定义事件(如I/O 完成)的发生可以暂停任何作业的活动。处理器保存某些上下文(如程序计数器和其他寄存器),然后跳转到中断处理程序中,处理中断,然后恢复用户被中断作业或其他作业的处理。
设计出一个协调各种不同活动的系统软件是非常困难的。
在任何时刻都有许多作业在运行中,每个作业都包括要求按顺序执行的很多步骤。由于缺乏能够在所有活动中进行协调和合作的系统级的方法,程序员只能基于他们对操作系统所控制的环境的理解,采用自己的特殊方法。然而这种方法是很脆弱的,尤其对于一些程序设计中的小错误,因为这些错误只有在很少见的事件序列发生时才会出现。由于需要从应用程序软件错误和硬件错误中区分出这些错误,因而诊断工作是很困难的。即使检测出错误,也很难确定其原因,因为很难再现错误产生的精确场景。一般而言,产生这类错误有4 个主要原因:- 不正确的同步:即一个例程必须挂起,等待系统中其他地方的某一事件。例如,一个程序启动了一个I/O 读操作,在继续进行之前必须等到缓冲区中有数据。在这种情况下,需要来自其他例程的一个信号,而设计不正确的信号机制可能导致信号丢失或接收到重复信号。
- 失败的互斥:多个用户或程序试图同时使用一个共享资源的情况。因此必须有某种互斥机制,以保证一次只允许一个例程对一部分数据执行事务处理。很难证明这类互斥机制的实现对所有可能的事件序列都是正确的。
- 不确定的程序操作:一个特定程序的结果只依赖于该程序的输入,而并不依赖于共享系统中其他程序的活动。但是,当程序共享内存并且处理器控制它们交错执行时,它们可能会因为重写相同的内存区域而发生不可预测的相互干扰。因此,程序调度顺序可能会影响某个特定程序的输出结果。
- 死锁:很可能有两个或多个程序相互挂起等待。例如,两个程序可能都需要两个I/O 设备执行一些操作(如从磁盘复制到磁带)。一个程序获得了一个设备的控制权,而另一个程序获得了另一个设备的控制权,它们都等待对方释放自己想要的资源。这样的死锁依赖于资源分配和释放的时机安排。
解决这些问题需要一种系统级的方法监控处理器中不同程序的执行。进程的概念为此提供了基础。进程可以看做是由三部分组成的:
- 一段可执行的程序
- 程序所需要的相关数据(变量、工作空间、缓冲区等)
- 程序的执行上下文
最后一部分是根本。执行上下文又称做进程状态(process state),是操作系统用来管理和控制进程所需的内部数据。这种内部信息和进程是分开的,因为操作系统信息不允许被进程直接访问。上下文包括操作系统管理进程以及处理器正确执行进程所需要的所有信息。包括了各种处理器寄存器的内容,如程序计数器和数据寄存器。它还包括操作系统使用的信息,如进程优先级以及进程是否在等待特定I/O 事件的完成。
图2.8 给出了一种进程管理的方法。两个进程存在于内存的某些部分。给每个进程(包含程序、数据和上下文信息)分配一块存储器区域,并且在由操作系统建立和维护的进程表中进行记录。进程表包含记录每个进程的表项,表项内容包括:
- 指向包含进程的存储块地址的指针;
- 该进程的部分或全部执行上下文。执行上下文的其余部分存放在别处,可能和进程自己保存在一起(如图2.8 所示),通常也可能保存在内存里一块独立的区域中。
- 进程索引寄存器(process index register)包含当前正在控制处理器的进程在进程表中的索引。
- 程序计数器指向该进程中下一条待执行的指令。
- 基址寄存器(base register)和界限寄存器(limit register)定义了该进程所占据的存储器区域:
- 基址寄存器中保存了该存储器区域的开始地址,
- 界限寄存器中保存了该区域的大小(以字节或字为单位)。
程序计数器和所有的数据引用相对于基址寄存器被解释,并且不能超过界限寄存器中的值,这就可以保护内部进程间不会相互干涉。
在图2.8 中,进程索引寄存器表明进程B正在执行。以前执行的进程被临时中断,在A中断的同时,所有寄存器的内容被记录在它的执行上下文环境中,以后操作系统就可以执行进程切换,恢复进程A的执行。进程切换过程包括保存B的上下文和恢复A 的上下文。当在程序计数器中载入指向A的程序区域的值时,进程A 自动恢复执行。
(点击查看大图)图2.8 典型的进程实现方法 |
进程被当做数据结构来实现。一个进程可以是正在执行,也可以是等待执行。任何时候整个进程状态都包含在它的上下文环境中。这个结构使得可以开发功能强大的技术,以确保在进程中进行协调和合作。在操作系统中可能会设计和并入一些新的功能(如优先级),这可以通过扩展上下文环境以包括支持这些特征的新信息。在本书中,将有很多关于使用进程结构解决在多道程序设计和资源共享中出现的问题的例子。
2.3.2 内存管理
通过支持模块化程序设计的计算环境和数据的灵活使用,用户的要求可以得到很好的满足。系统管理员需要有效且有条理地控制存储器分配。操作系统为满足这些要求,担负着5 个基本的存储器管理责任:
- 进程隔离:操作系统必须保护独立的进程,防止互相干涉各自的存储空间,包括数据和指令。
- 自动分配和管理:程序应该根据需要在存储层次间动态地分配,分配对程序员是透明的。操作系统有效地实现分配问题,仅在需要时才给作业分配存储空间。
- 支持模块化程序设计:程序员应该能够定义程序模块,并且动态地创建、销毁模块,动态地改变模块大小。
- 保护和访问控制:不论在存储层次中的哪一级,存储器的共享都会产生一个程序访问另一个程序存储空间的潜在可能性。当一个特定的应用程序需要共享时,这是可取的。但在别的时候,它可能威胁到程序的完整性,甚至威胁到操作系统自身。操作系统必须允许一部分内存可以由各种用户以各种方式进行访问。
- 长期存储:许多应用程序需要在计算机关机后长时间保存信息。
在典型情况下,操作系统使用虚拟存储器和文件系统机制来满足这些要求。
文件系统实现了长期存储,它在一个有名字的对象中保存信息,这个对象称做文件。对操作系统来说,文件是访问控制和保护的一个有用单元。虚拟存储器机制允许程序从逻辑的角度访问存储器,而不考虑物理内存上可用的空间数量。虚拟存储器的构想是为了满足有多个用户作业同时驻留在内存中的要求,这样,当一个进程被写出到辅助存储器中并且后继进程被读入时,在连续的进程执行之间将不会脱节。由于进程大小不同,如果处理器在很多进程间切换,则很难把它们紧密地压入内存中,因此引进了分页系统。在分页系统中,进程由许多固定大小的块组成,这些块称做页。程序通过虚地址(virtualaddress)访问字,虚地址由页号和页中的偏移量组成。进程的每一页都可以放置在内存中的任何地方,分页系统提供了程序中使用的虚地址和内存中的实地址或物理地址之间的动态映射。
有了动态映射硬件,下一逻辑步骤是消除一个进程的所有页同时驻留在内存中的要求。一个进程的所有页都保留在磁盘中,当进程执行时,一部分页在内存中。如果需要访问的某一页不在内存中,存储管理硬件可以检测到,然后安排载入这个缺页。这个配置称做虚拟内存,如图2.9所示。
图2.9 虚拟存储器概念 |
(点击查看大图)图2.10 虚拟存储器寻址 |
处理器硬件和操作系统一起提供给用户“虚拟处理器”的概念,而“虚拟处理器”有对虚拟存储器的访问权。这个存储器可以是一个线性地址空间,也可以是段的集合,而段是可变长度的连续地址块。不论哪种情况,程序设计语言的指令都可以访问虚拟存储器区域中的程序和数据。可通过给每个进程一个唯一的不重叠的虚拟存储器空间来实现进程隔离;可以通过使两个虚拟存储器空间的一部分重叠来实现内存共享;文件可用于长期存储,文件或其中一部分可以复制到虚拟存储器中供程序操作。
图2.10 显示了虚拟存储器方案中的寻址关系。存储器由内存和低速的辅助存储器组成,内存可直接访问到(通过机器指令),外存则可以通过把块载入内存间接访问到。地址转换硬件(映射器)位于处理器和内存之间。程序使用虚地址访问,虚地址将映射成真实的内存地址。如果访问的虚地址不在实际内存中,实际内存中的一部分内容将换到外存中,然后换入所需要的数据块。在这个活动过程中,产生这个地址访问的进程必须被挂起。操作系统设计者的任务是开发开销很少的地址转换机制,以及可以减小各级存储器级间交换量的存储分配策略。
2.3.3 信息保护和安全
有一些通用工具可以嵌入支持各种保护和安全机制的计算机和操作系统内部。总之,我们关心对计算机系统的控制访问和其中保存的信息。
大多数与操作系统相关的安全和保护问题可以分为4 类:
- 可用性:保护系统不被打断。
- 保密性:保证用户不能读到未授权访问的数据。
- 数据完整性:保护数据不被未授权修改。
- 认证:涉及用户身份的正确认证和消息或数据的合法性。
2.3.4 调度和资源管理
操作系统的一个关键任务是管理各种可用资源(内存空间、I/O 设备、处理器),并调度各种活动进程使用这些资源。任何资源分配和调度策略都必须考虑三个因素:
- 公平性:通常希望给竞争使用某一特定资源的所有进程提供几乎相等和公平的访问机会。
- 有差别的响应性:另一方面,操作系统可能需要区分有不同服务要求的不同作业类。操作系统将试图做出满足所有要求的分配和调度决策,并且动态地做出决策。例如,如果一个进程正在等待使用一个I/O 设备,操作系统会尽可能迅速地调度这个进程,从而释放这个设备以方便其他进程使用。
- 有效性:操作系统希望获得最大的吞吐量和最小的响应时间,并且在分时的情况下,能够容纳尽可能多的用户。这些标准互相矛盾,在给定状态下寻找适当的平衡是操作系统中一个正在进行研究的问题。
此外,系统活动的度量对监视性能并进行调节是非常重要的。
图2.11 给出了多道程序设计环境中涉及进程调度和资源分配的操作系统主要组件。操作系统中维护着多个队列,每个队列代表等待某些资源的进程的简单列表。
- 短期队列由在内存中(或至少最基本的一小部分在内存中)并等待处理器可用时随时准备运行的进程组成。任何一个这样的进程都可以在下一步使用处理器,究竟选择哪一个取决于短期调度器,或者称为分派器( dispatcher)。一个常用的策略是依次给队列中的每个进程一定的时间,这称为时间片轮转技术,时间片轮转技术使用了一个环形队列。另一种策略是给不同的进程分配不同的优先级,根据优先级进行调度。
- 长期队列是等待使用处理器的新作业的列表。操作系统通过把长期队列中的作业转移到短期队列中,实现往系统中添加作业,这时内存的一部分必须分配给新到来的作业。因此,操作系统要避免由于允许太多的进程进入系统而过量使用内存或处理时间。每个I/O 设备都有一个I/O 队列,可能有多个进程请求使用同一个I/O 设备。所有等待使用一个设备的进程在该设备的队列中排队,同时操作系统必须决定把可用的I/O 设备分配给哪一个进程。
如果发生了一个中断,则操作系统在中断处理程序入口得到处理器的控制权。进程可以通过服务调用明确地请求某些操作系统的服务,如I/O 设备处理服务。在这种情况下,服务调用处理程序是操作系统的入口点。在任何情况下,只要处理中断或服务调用,就会请求短期调度器选择一个进程执行。
前面所述的是一个功能描述,关于操作系统这部分的细节和模块化的设计,在各种系统中各不相同。操作系统中这方面的研究大多针对选择算法和数据结构,其目的是提供公平性、有差别的响应性和有效性。
图2.11 用于多道程序设计的操作系统的主要组件 |
2.4 现代操作系统的特征
促使操作系统发展的硬件因素主要有:
- 包含多处理器的计算机系统、高速增长的机器速度、高速网络连接和容量不断增加的各种存储设备。
- 多媒体应用、Internet 和Web 访问、客户/服务器计算等应用领域也影响着操作系统的设计。
- 在安全性方面,互联网的访问增加了潜在的威胁和更加复杂的攻击,例如病毒、蠕虫和黑客技术。
不仅需要修改和增强现有的操作系统体系结构,而且需要有新的操作系统组织方法。在实验用和商用操作系统中有很多不同的方法和设计要素,大致可以分为:
- 微内核体系结构
- 多线程
- 对称多处理
- 分布式操作系统
- 面向对象设计
至今,大多数操作系统都有一个单体内核,操作系统应该提供的功能由这些大内核提供,包括调度、文件系统、网络、设备驱动器、存储管理等。典型情况下,这个大内核是作为一个进程实现的,所有元素都共享相同的地址空间。微内核体系结构只给内核分配一些最基本的功能,包括地址空间、进程间通信(简称IPC)和基本的调度。其他的操作系统服务都是由运行在用户态下且与其他应用程序类似的进程提供,这些进程可根据特定的应用和环境需求进行定制,有时也称这些进程为服务器。这种方法把内核和服务程序的开发分离开,可以为特定的应用程序或环境要求定制服务程序。微内核方法可以使系统结构的设计更加简单、灵活,很适合于分布式环境。实质上,微内核可以以相同的方式与本地和远程的服务进程交互,使分布式系统的构造更为方便。
多线程技术是指把执行一个应用程序的进程划分成可以同时运行的多个线程。线程和进程有以下差别:
- 线程:可分派的工作单元。包括处理器上下文环境(包含程序计数器和栈指针)和栈中自己的数据区域(为允许子程序分支)。线程顺序执行,并且是可中断的,这样处理器可以转到另一个线程。
- 进程:一个或多个线程和相关系统资源(如包含数据和代码的存储器空间、打开的文件和设备)的集合。这紧密对应于一个正在执行的程序的概念。通过把一个应用程序分解成多个线程,程序员可以控制应用程序的模块性和应用程序相关事件的时间安排。
多线程对执行许多本质上独立、不需要串行处理的应用程序是很有用的,例如监听和处理很多客户请求的数据库服务器。在同一个进程中运行多个线程,在线程间来回切换所涉及的处理器开销要比在不同进程间进行切换的开销少。线程对构造进程是非常有用的,进程作为操作系统内核的一部分,将在第3 章中讲述。
到现在为止,大多数单用户的个人计算机和工作站基本上都只包含一个通用的微处理器。随着性能要求的不断增加以及微处理器价格的不断降低,计算机厂商引进了拥有多个微处理器的计算机。为实现更高的有效性和可靠性,可使用对称多处理(SMP)技术。对称多处理不仅指计算机硬件结构,而且指反映该硬件结构的操作系统行为。对称多处理计算机可以定义为具有以下特征的一个独立的计算机系统:
- 有多个处理器。
- 这些处理器共享同一个内存和I/O 设备,它们之间通过通信总线或别的内部连接方案互相连接。
- 所有处理器都可以执行相同的功能(因此称为对称)。
近年来,在单芯片上的多处理器系统(也称为单片多处理器系统)已经开始广泛应用。无论是单片多处理器还是多片对称多处理器(SMP),许多设计要点是一样的。
对称多处理操作系统可调度进程或线程到所有的处理器运行。对称多处理器结构比单处理器结构具有更多的潜在优势,如下所示:
- 性能:如果计算机完成的工作可组织为让一部分工作可以并行完成,那么有多个处理器的系统将比只有一个同类型处理器的系统产生更好的性能,如图2.12 所示。对多道程序设计而言,一次只能执行一个进程,此时所有别的进程都在等待处理器。对多处理系统而言,多个进程可以分别在不同的处理器上同时运行。
图2.12 多道程序设计和多道处理 |
- 可用性:在对称多处理计算机中,由于所有的处理器都可以执行相同的功能,因而单个处理器的失败并不会使机器停止。相反,系统可以继续运行,只是性能有所降低。
- 增量增长:用户可以通过添加额外的处理器来增强系统的功能。
- 可扩展性:生产商可以根据系统配置的处理器的数量,提供一系列不同价格和性能特征的产品。
特别需要注意的是,这些只是潜在的优点,而不是确定的。操作系统必须提供发掘对称多处理计算机系统中并行性的工具和功能。
多线程和对称多处理总是被放在一起讨论,但它们是两个独立的概念。即使在单处理器机器中,多线程对结构化的应用程序和内核进程也是很有用的。由于多个处理器可以并行运行多个进程,因而对称多处理计算机对非线程化的进程也是有用的。但是,这两个设施是互补的,一起使用将会更有效。
对称多处理技术一个很具有吸引力的特征是多处理器的存在对用户是透明的。操作系统负责在多个处理器中调度线程或进程,并且负责处理器间的同步。本书讲述了给用户提供单系统外部特征的调度和同步机制。另外一个不同的问题是给一群计算机(多机系统)提供单系统外部特征。在这种情况下,需要处理的是一群实体(计算机),每一个都有自己的内存、外存和其他I/O 模块。分布式操作系统使用户产生错觉,使多机系统好像具有一个单一的内存空间、外存空间以及其他的统一存取措施,如分布式文件系统。尽管集群正变得越来越流行,市场上也有很多集群产品,但是,分布式操作系统的技术发展水平落后于单处理器操作系统和对称多处理操作系统。我们将在第八部分分析这类系统。
操作系统设计的另一个改革是使用面向对象技术。面向对象设计的原理用于给小内核增加模块化的扩展上。在操作系统一级,基于对象的结构使程序员可以定制操作系统,而不会破坏系统的完整性。面向对象技术还使得分布式工具和分布式操作系统的开发变得更容易。
2.5 虚拟机
2.5.1 虚拟机和虚拟化
一般来说,应用程序直接运行在操作系统之上,操作系统之下的硬件可能是个人计算机或是服务器。但无论是哪个,在同一时间里只能运行一个操作系统。因此,应用程序提供商必须针对目标运行平台对程序的一些部分进行相应的修改。而针对这个难题的一种解决办法就是虚拟化。
虚拟化技术使得一个硬件平台(个人计算机或者服务器)可以同时运行多种不同的操作系统或者是同一种操作系统的多个版本。对于具备虚拟化技术的机器来说,可以在单个机器上管理多种应用程序,即使这些应用程序是为不同的操作系统开发的。
本质上,这个机器的主系统可以支持很多虚拟机,而每一台虚拟机可以具备某个特定操作系统的特性,甚至一些虚拟化技术能让虚拟机具备特定硬件平台的特性。
虚拟化技术在处理老版本程序的兼容性问题以及通过虚拟化来丰富单台计算机所能运行的应用程序种类方面特别普遍。不同公司的虚拟机技术的体系架构不尽相同。下图是比较典型的架构。
- 虚拟机管理程序(VMM)运行在宿主操作系统上。模拟硬件设备的虚拟机由VMM支持和管理。每个虚拟机上都运行一个独立的操作系统。VMM负责管理这些操作系统与真正的处理器、存储介质及网络之间的通信。
- 在执行程序时,VMM会将处理器的控制权交给虚拟机上的操作系统。
- 如果虚拟机之间需要通信,大多数情况下虚拟机会使用虚拟的网络来相互通信。
- 上述架构最关键的优势是,VMM提供了一个应用透明的、可编程的中间层,将应用程序执行环境与下层的物理机和主操作系统分开,从而可以更大地发挥硬件的功能。
2.5.2 虚拟机架构
。。。
2.6 针对多处理器和多核的操作系统设计考虑因素
。。。
2.6.1 对称多处理器计算机的操作系统设计考虑因素
。。。
2.6.2 多核计算机的操作系统设计考虑因素
。。。
2.7 微软windows系统简介
。。。
2.8 传统的UNIX系统
。。。
2.9 现代UNIX系统
。。。
2.10 Linux操作系统
。。。
2.11 Linux Vserver虚机器机构