目录
七、操作系统
7.1 引言
计算机系统是由两个主要部分组成的:硬件和软件。硬件是计算机的物理设备,软件是使得硬件能正常工作的程序的集合。计算机软件分为两大类:操作系统和应用程序。应用程序使用计算机硬件来解决问题,操作系统则控制应用程序对硬件的访问。
7.1.1 操纵系统
操作系统是一个非常复杂的系统,因此很难给出一个普遍认同的简单定义,下面给出一个差不多的定义:操作系统是计算机硬件和用户(程序和人)之间的接口,它使得其他程序更加方便有效地运行,并能方便地对计算机硬件和软件资源进行访问。
操作系统地两个主要设计目标:有效地使用硬件、容易地使用资源。
7.1.2 自举过程
操作程序为其他程序提供支持,负责将它们装入内存并运行。但是操作系统本身也是程序,它需要被装入内存运行,ROM技术很好的解决了这个问题。
将操作系统存储在ROM中,CPU的程序计数器指向ROM的开始处,当计算机通电时,CPU从ROM中读取指令并执行。但这种方案是很低效的,ROM如果过小,就装不下操作系统,要装入操作系统后,内存的很大一部分都由ROM构成,留给其他程序的空间就会很小。
如今的解决方案是:很小的一部分内存用ROM构成,其中有称为自举程序的小程序,这个程序负责在计算机启动时将操作系统装入RAM并由CPU运行操作系统。
7.2 演化
1. 批处理系统
批处理系统设计于20世纪50年代,目的是控制大型计算机。当时的计算机非常庞大,使用穿孔卡片输入数据,用行式打印机输出结果,用磁带设备作为辅助存储介质。
每个要运行的程序叫作业。想要运行程序的程序员通过穿孔卡片将程序和数据输入见算计,并向控制器发出作业请求。如果程序运行成功,打印结果,否则报错。
这个时代的操作系统非常简单:它们只保证计算机所有资源从一个作业转移到另一个作业。
2. 分时系统
为了有效使用计算机资源,多道程序的概念被引入。它将多个作业同时装入内存,并且仅当该资源可用时分配给需要它的作业。
多道程序带来了分时的概念:资源可以被不同的作业分享,每个作业分到一段时间来使用资源。由于计算机运行速度很快,所以分时系统对用户是隐藏的(例如,不同的程序都有都有一微秒的时间来使用同一个资源,由于运行速度很快,用户感觉不到自己正在使用的程序在等待使用资源)。
调度:给不同的程序分配资源并决定哪一个程序什么时候使用哪一种资源。
进程:一个作业是一个要运行的程序,一个进程则是在内存中等待分配资源的程序。
3. 个人系统
当个人计算机产生后,需要有一类适合这类计算机的操作系统,于是,单用户操作系统应运而生,如DOS(磁盘操作系统)。
4. 并行系统
在同一个计算机中安装多个CPU,每个CPU可以处理一个程序或程序的一部分,这样在同一时间就可以并行处理多项任务。
5. 分布式系统
网络化和网络互联的发展扩大了操作系统的内涵。程序可以在一台计算机上运行一部分,在另外一台计算机上运行另一部分,只要它们通过网络连接即可。资源可以是分布式的,一个程序需要的文件可能分布在世界的不同地方。分布式系统结合了以往系统的特点和新的功能。
6. 实时系统
指在特定时间限制内完成任务。它们被用在实时程序中,这些程序监控、响应或控制外部过程或环境。在交通控制、病人监控或军事控制系统中可以找到实时系统的例子。
7.3 组成部分
操作系统由五个部分组成:用户界面(命令解释程序)、内存管理器、进程管理器、设备管理器、文件管理器。
7.3.1 用户界面
每个操作系统都有用户界面,是用来接收用户(进程)的输入并向操作系统解释这些请求的程序。一些操作系统(比如Unix)的用户界面被称为命令解释程序(shell),在另一些操作系统中称为窗口,以指明它是由菜单驱动的GUI(图形用户接口)。
7.3.2 内存管理器
计算机中的存储器的容量越来越大,所运行的程序和处理的数据也越来越大,内存分配必须进行管理以免“内存溢出”的错误。操作系统按照内存管理可分为两大类:单道程序和多道程序。
1. 单道程序
单道程序属于过去,但它还是值得学习。在单道程序中,大多数内存用来装载单一的程序,仅仅一小部分用来装操作系统,整个程序装入内存中,运行结束后,程序由其他要运行的程序取代。
单道程序存在一些问题:
程序必须能够载入内存才能运行,如果内存过小,一些程序将无法运行。
当一个程序运行时,其他程序不能运行。如果运行中的程序在使用输入输出设备,CPU就会处于空闲状态,但由于输入输出设备的运行速度与CPU相差很大,所以CPU的使用效率会很低。
2. 多道程序
同一时刻可以将多个程序装入内存并且能够同时被执行,CPU轮流为其服务。
多道程序有四种调度模式,两种属于非交换范畴(分页调度、分区调度),两种属于交换范畴(请求分页调度、请求分段调度)。
① 分区调度
在这种模式中,内存被分为长度不一的几个分区,每个分区保存一个程序。CPU在各程序之间交替服务。它由一个程序开始,执行一些指令,直到有输入输出操作或者分配给程序的时限到达为止,CPU保存最近使用的指令的内存地址后执行下一个程序,每个程序都是如此。CPU可以进行优先级管理,用于控制分配给每个程序的时间。
在这种模式下,每个程序完全载入内存,并使用连续的地址,但有一些小问题:
分区大小必须由内存管理器预先决定。如果分区小了,有些程序就不能载入内存;如果分区大了,就会出现空闲区。
即使分区在刚开始的时候比较合适,但随着新程序交换载入内存后可能会出现空闲区。
当空闲区过多,内存管理器能够紧缩分区并删除空闲区创建新区,但这需要额外开销。
② 分页调度
分页调度提高了分区调度的效率,它将内存分为大小相等的若干个部分(帧),同时程序也被分为大小相等的若干个页。页和帧的大小通常是一样的,并且与系统用于从存储设备中提取信息的块的大小相同。
页被载入到内存的帧,如果一个程序被分为3页,它就需要3帧来存放。在分页调度下,程序不必占用连续的地址,连续的页可以占据不连续的帧。分页调度的优势在于,一个6页的程序在内存中有6个空着的帧时就可以载入运行(即使这六个帧不连续),但是如果内存中不够6个空闲帧,程序仍然不能载入。
③ 请求分页调度
分页调度不需要程序装载在连续的内存空间中,但仍需要程序整个载入。请求分页调度改变了这种限制。在请求分页调度中,程序被分为若干页,但页可以依次载入内存并运行,然后被下一个页代替,内存可以同时载入多个程序的页,一个页可以载入任意空闲帧,并且每个程序的所有页不必全部载入内存。
④ 请求分段调度
在分页调度中,不像程序员以模块来考虑程序,程序实际上是分成大小相等的页。在请求分段调度中,程序将按程序员的角度划分成段(主程序和子程序等),并载入内存运行,然后被来自同一程序或其他程序的其他模块替代。内存被分为大小相等的段,但由于程序的划分是按照程序员角度的,所以每个模块并不一定一样长,所以在载入内存段后,可能会出现空闲区。
⑤ 请求分页和分段调度
结合了请求分页和请求分段两种调度模式的优点以提高系统效率。程序按程序员角度划分为多个模块,每个模块又划分成若干个大小相等的页,内存分为若干大小相等的帧,然后程序按模块依次载入内存运行。
3. 虚拟内存
请求分页调度和请求分段调度意味着当程序运行时,程序的一部分在内存上,另一部分在硬盘中。例如,10 MB的内存可以运行10个3 MB的程序,总共30 MB,有10 MB在内存中,20 MB在硬盘上。实际只有10 MB的内存,却有30 MB的虚拟内存。虚拟内存就是将内存中的程序所在硬盘的空间也看作是内存的一部分。
7.3.3 进程管理器
1. 程序、作业、进程
程序:是由程序员编写的一组稳定的指令,存在磁盘(或磁带)上,它可能会也可能不会成为作业。
作业:从一个程序被选中执行,到其运行结束并再次成为一个程序的这段过程中,这个程序就称为作业。作业可能会或不会被执行,或者驻留在磁盘上等待调入内存,或者在内存中等待CPU执行等。作业一定是程序,程序不一定是作业。
进程:进程是一个运行中的程序,换句话说,只要作业装入内存就是进程。 进程一定是作业,作业不一定是进程。
2. 状态图
当明白程序、作业和进程的定义之后,它们三者之间的关系就很明显了。
一个程序被选中执行后就成为了作业并进入保持状态,直到它载入内存之前都保持这个状态。当作业部分或整体载入内存,就变为进程,同时进入就绪状态。它在内存中保持这个状态直到CPU运行它,这时转为运行状态,运行状态后可能出现三种情况:
进程运行直至它需要I/O资源。
进程可能耗尽所分配的时间片。
进程终止。
第一种情况,进程进入等待状态直到输入输出结束;第二种情况下,进程直接进入就绪状态;第三种情况下,进程进入终止状态,并不再是进程。进程进入终止状态前在就绪、执行、等待三种状态间转换。如果系统使用虚拟内存,状态图会更加复杂。
3. 调度器
将一个作业或进程从一个状态改变为另一个状态。进程管理器使用了两个调度器:作业调度器和进程调度器。
作业调度器:将一个作业从保持状态转入就绪状态,或是从运行状态转为终止状态。作业调度器负责从作业中创建一个进程和终止一个进程。
进程调度器:将一个进程从一个状态转入另一个状态。当CPU准备执行进程时,它将进程从就绪状态转入执行状态;当进程在需要使用I/O设备时,它将进程从执行状态转入等待状态;当输入输出结束,它将进程转入就绪状态。
其他调度器:一些操作系统使用其他类型的调度器使进程之间的转换更为有效。
4. 队列
事实上,会有很多作业和进程相互竞争计算机资源。当一个作业进入内存,其他的就必须等待直到有可用的空间;或是当一个进程在使用CPU,其他进程就要等待直到CPU空闲。为处理多个进程和作业,进程管理器使用队列。与每一作业或进程相关的是存有这些作业和进程信息的作业控制块和进程控制块。进程管理器在队列中存储的不是作业或进程,而是作业控制块或进程控制块。
作业队列用来保存等待内存的作业;就绪队列保存已经准备好等待执行的进程;I/O队列保存那些等待使用I/O设备的进程。
进程管理器可以用多种策略从队列中选择下一个作业或进程,可以是先入先出、最短长度优先、最高优先级等。
5. 进程同步
所有的进程管理思想都是使得拥有不同资源的不同进程同步。只要资源可以被多个用户(进程)同时使用,它就可能会有两种问题状态:死锁和饥饿。
1. 死锁
假定有两个进程A和B,进程A占有了一个名为File1的文件,进程B占有了File2.A只有得到File2才能释放File1,B只有得到File1才能释放File2.这时两个进程就无法继续运行下去。
死锁发生在操作系统允许一个进程运行,而不用首先检查它所需资源是否准备好,是否允许这个进程占有资源直到它不需要为止。操作系统中需要有一些措施来防止死锁。一种解决方法是当所需要的资源不空闲时,不允许程序运行,但这回引发另一种问题,另一种方法是限制进程占有资源的时间。
当操作系统没有对进程的资源进行限制时将会发生死锁。
死锁发生需要4个必要条件:
互斥:一个资源只能被一个进程占有;
资源占有:即使在获取其他资源之前无法使用它,一个进程仍然占有这个资源;
抢先:操作系统不能临时对资源重新分配;
循环等待:所有进程和资源包含在一个循环里。
对死锁来说,这四个条件必须同时存在,但是它们并不一定能引起死锁。如果它们其中之一不出现,就不会发生死锁。
2. 饥饿
饥饿发生在操作系统对进程分配资源有太多限制的时候。例如,假如一个操作系统规定一个进程只有在需要的所有资源都被其占有时才能执行。
进程A需要File1和File2两个文件才能执行。File1正在被B使用,File2正在被C使用。进程B首先释放File1,但是A不能执行,因为缺少File2;与此同时,进程D只需要File1就被允许执行了。当C释放File2时,A仍然不能执行,因为File1被D所占有。这就是饥饿。
7.3.4 设备管理器
设备管理器负责访问输入/输出设备,让输入/输出设备使用起来更有效。这里简单列出设备管理器的功能:
设备管理器不停地监视所有输入/输出设备,以保证它们能够正常运行。管理器同样也需要知道何时设备已经完成一个进程地服务,而且能够为队列中的下一个进程服务;
设备管理器为每一个输入/输出设备维护一个队列,或是为类似地输入/输出设备维护一个或多个队列。例如,如果系统中有两台告诉打印机,管理器能够分别用一个队列维护一个设备,或是用一个队列维护两个设备;
设备管理器控制用于访问输入/输出设备的不同策略。例如,可以用先入先出法来维护一个设备,用最短长度优先来维护另一个设备。
7.3.5 文件管理器
现今的操作系统使用文件管理器来控制对文件的访问,下面简述文件管理器的功能:
文件管理器控制文件的访问。只有那些获得允许的应用程序才能够访问,访问方式也可以不同。例如,一个进程也许可以读取文件,但却不允许写操作。另一个进程也许被允许执行文件和进程,但却不允许读取文件的内容;
文件管理器管理文件的创建、删除和修改;
文件管理器可以给文件命名;
文件管理器管理文件的存储:怎样存储,存在哪里等;
文件管理器负责归档和备份。
7.4 操作系统
介绍3种比较熟悉的操作系统。
7.4.1 UNIX
UNIX由贝尔实验室在1969年首先开发出来,是多用户、多道程序、可移植的操作系统,它被设计用来方便编程、文本处理、通信。
UNIX由4个主要部分构成:内核、命令解释器、一组标准工具和应用程序。
内核:包含操作系统最基本的部分:内存管理、进程管理、设备管理和文件管理。系统其他部分均调用内核来执行这些服务。
命令解释器:接收和解释用户输入的命令。
工具:工具是UNIX的标准程序,它为用户提供支持。常用的三个工具是:文本编辑器、搜索程序和排序程序。
应用:指一些程序,不是操作系统发布中的标准部分。它们是由系统管理员、程序员或用户编写的,提供了对系统的扩展能力。
7.4.2 Linux
1991年,芬兰Helsinki大学的学生Linus Torvalds开发了一个新的操作系统。1997年发布的Linus 2.0内核称为商业操作系统,它具有传统UNIX的所有特性。
1. 组成
内核:负责处理所有属于内核的职责,如内存管理、进程管理、设备管理和文件管理。
系统库:含有一组被应用程序使用的函数(包含命令解释器),用于与内核交互。
系统工具:系统工具是使用系统库提供的服务,执行管理任务的各个程序。
2. 网络功能
Linux支持第六章讨论的标准因特网协议。它支持三层:套接字接口、协议驱动和网络设备驱动。
3. 安全
Linux的安全机制提供了传统上UNIX定义的安全特性,如身份验证和访问控制。
7.4.3 Windows
20世纪80年代后期,在Dave Cutler 的领导下,微软开始开发替代 MS-DOS(微软磁盘操作系统)的新的单用户操作系统。Windows就是结果。
1. 设计目标
可扩展性:Windows被设计成具有多层的模块化体系结构。意图是允许高层随时间而改变,而不影响底层。
可移植性:Windows是用C或C++编写的,这个语言是独立于它所运行的计算机的机器语言的。
可靠性:Windows被设计成能处理包括防止恶意软件的错误条件。
兼容性:Windows被设计成能运行为其他操作系统编写的程序,或Windows早期版本。
性能:Windows被设计成对运行在操作系统顶部的应用程序,具有快速响应时间。
2. 体系结构
Windows使用层次体系结构。
HAL:硬件抽象层为上层隐藏了硬件差异。
内核:内核是操作系统的心脏。它是面向对象软件的一个片段,该面向对象的软件把任何实体都看成对象。
执行者:Windows执行者为整个操作系统提供服务。它由六个子系统构成:对象管理器、安全引用监控器、进程管理器、虚拟内存管理器、本地过程调用工具和I/O管理。有些子系统(如对象管理器)被加到Windows中,是因为它面向对象的本质。执行者运行在内核态(特权)。
环境子系统:这些子系统被设计用来允许运行那些为Windows、其他操作系统或Windows早期版本设计的应用程序。运行为Windows设计的应用程序的本地子系统称为Win32。环境子系统运行在用户态(无特权)。