操作系统之哲学原理第二版.pdf
http://www.100md.com
2020年11月16日
![]() |
| 第1页 |
![]() |
| 第9页 |
![]() |
| 第17页 |
![]() |
| 第30页 |
![]() |
| 第38页 |
![]() |
| 第353页 |
参见附件(18140KB,427页)。
《操作系统之哲学原理(第2版)》层次丰富、涵盖操作系统的所有核心内容,适合作为国内高校计算机及相关专业本科生操作系统课程的教材,也是了解计算机操作系统原理不可多得的参考书。

内容简介
操作系统是计算机系统的核心系统软件,负责控制和管理整个系统,使之协调工作。本书对操作系统的核心内容进行了全面分析,包括操作系统的发展历史和基本概念、进程与线程、内存管理、文件系统、输入与输出、多核环境下的进程调度和操作系统设计。本书用大量生活实例,生动地解释了操作系统中的主要难点和模糊点:锁的实现、同步机制的发展轴线、纯粹分段到段页式的演变、多核环境下的进程同步与调度和操作系统设计等内容。本书重点突出、逻辑清晰、内容连贯,便于学生顺利掌握操作系统的核心内容。
作者简介
邹恒明,美国密歇根大学博士。曾任职美国IBM、国家数据公司、朗讯、EMC公司8年多。在IBM和EMC分别从事AIX操作系统和Engenity存储操作系统的研发,其中包括911中挽摩根斯坦利公司于既倒的、美国唯yi的“英雄软件”SRDF。2007年在中国金融期货交易系统(股指期货)专家测评中担任软件测评组长。2004年以来在上海交大研究、执教操作系统和算法设计等14门课程多年。
本书内容安排
为清楚地阐述操作系统的哲学原理,也为了使内容显得紧凑,逻辑上一气呵成,本书只选择了操作系统的核心内容进行分析,放弃了对操作系统核心以外内容,如安全、多媒体系统、虚拟机技术、光盘技术等的论述。本书集中精力对操作系统发展的历史背景、进程与线程、内存管理、文件系统、输入与输出、多核环境下的进程调度和操作系统设计进行了哲学原理层面上的分析与论述,而将安全、多媒体、虚拟机等技术留给别的专业书籍进行论述。对内容的这种安排有如下好处:
可使本书重点突出、逻辑清晰、内容连贯,便于学生顺利掌握操作系统的核心与关键。
操作系统的核心内容经过长久的研究与实践,已经变得较为稳定并且形成了众所公认的标准,讲解起来没有歧义。
操作系统的非核心部分由于研究的时间短,工业界参与的程度较低,并无公认的标准,论述起来要么不全面,要么显得凌乱,使刚刚接触操作系统的读者感到迷惑
只要掌握了核心内容的原理,读者便能通过自学掌握操作系统核心以外的知识。
本书覆盖全国硕士研究生入学统一考试计算机学科《研究生考试大纲》中操作系统部分全部内容。
本书分为8篇,分别是基础原理篇、进程原理篇、线程原理篇、内存原理篇、文件原理篇、10原理篇、多核原理篇和操作系统设计篇,内容结构如图4所示。
本书特点
本书从哲学的视角对操作系统阐述了独到的见解。从人类自然的行为规范推演到操作系统的设计,以一条逻辑主线演绎了整个操作系统的各种原理。本书的特点是抽象提升(即从哲学原理上阐述操作系统的各种原理与设计)、联系生活(即通过人所熟知的生活实例来分析操作系统)、模块整合(即将操作系统的各个模块通过举例连结起来)、逻辑贯通(即将操作系统的各种机制以一根逻辑主线的发展依次讲解)和系统关联即将涉及的其他学科知识点如体系结构和编译器等嵌入进来)。本书内容上更加新颖、系统上更加完整、逻辑上更加连贯、解说上更加易懂和层次上更加丰富的特点。
读者在阅读学习完本书后,将达到如下目标:
了解操作系统在计算机软硬件整个体系中的中心主导作用。
掌握操作系统的基本概念、原理、技术和实现机制。
理解操作系统原理背后的人文背景与历史动机。
运用操作系统知识来分析和解决问题。
掌握操作系统设计的原理,为以后设计操作系统打下基础。
这里需要提醒的是,本书阐述的是操作系统的原理,它不依赖于任何具体的实现,而是凌驾于所有具体商业操作系统的进程实现之上,即本书所阐述的思想和原理对所有操作系统都适用。但具体商业操作系统在应用这些原理时可以有很灵活的方式。事实上,具体的商业操作系统在应用这些原理时确实采取了不同的方式,有的更为精密,也有的更加精简。另外,由于我们注重的是原理,对个体机制实现时采取的数据结构通常不做详细的论述,而是点到为止。这是因为数据结构必须以真正的操作系统为蓝本进行讲解,而真正的商业操作系统使用的数据结构通常非常复杂,对此进行繁琐的讲解将把学生弄得晕头转向,而不利于对操作系统核心原理的把握。
操作系统之哲学原理第二版截图




操作系统之哲学原理 第2版
邹恒明 著
ISBN:978-7-111-36692-8
本书纸版由机械工业出版社于2012年出版,电子版由华章分社(北京华章图文信息有限公司)全球范围内制
作与发行。
版权所有,侵权必究
客服热线:+ 86-10-68995265
客服信箱:service@bbbvip.com
官方网址:www.bbbvip.com
新浪微博 @研发书局
腾讯微博 @yanfabook目录
前言
计算机的心智
操作系统的奥秘
操作系统之哲学原理
本书内容安排
基础原理篇
进程原理篇
线程原理篇
内存原理篇
文件原理篇
IO原理篇
多核原理篇
操作系统设计篇
本书特点
第一篇 基础原理篇
第1章 操作系统导论
引子:智者的挑战
1.1 人造与神造
1.2 程序是如何运行的
1.3 什么是操作系统
1.4 魔术与管理
1.5 用户程序与操作系统
1.6 操作系统的范畴
1.7 为什么学习操作系统
思考题
第2章 操作系统历史
引子:不能承受之真
2.1 第一阶段:状态机操作系统(1940年以前)
2.2 第二阶段:单一操作员单一控制端操作系统(20世纪40年代)
2.3 第三阶段:批处理操作系统(20世纪50年代)
2.4 第四代:多道批处理操作系统(20世纪60年代)2.5 第五代之一:分时操作系统(20世纪70年代)
2.6 第五代之二:实时操作系统
2.7 第六代:现代操作系统(1980年以后)
2.8 操作系统的演变过程
2.9 操作系统的未来发展趋势
2.10 讨论:操作系统虚拟化和虚拟化的操作系统
思考题
第3章 操作系统基本概念
引子:软件师的尴尬
3.1 计算机硬件基本知识
3.2 抽象
3.3 内核态和用户态
3.4 操作系统结构
3.5 进程、内存和文件
3.6 系统调用
3.7 壳
思考题
第二篇 进程原理篇
第4章 进程
引子:牛顿的困惑
4.1 进程概论
4.2 进程模型
4.3 多道编程的好处
4.4 进程的产生与消亡
4.5 进程的层次结构
4.6 进程的状态
4.7 进程与地址空间
4.8 进程管理
4.9 进程的缺陷
思考题
第5章 进程调度
引子:恐怖分子的调度
5.1 进程调度的定义5.2 进程调度的目标
5.3 先来先服务调度算法
5.4 时间片轮转算法
5.5 短任务优先算法
5.6 优先级调度算法
5.7 混合调度算法
5.8 其他调度算法
5.9 实时调度算法
5.10 进程调度的过程
5.11 高级议题:调度异常之优先级倒挂
思考题
第6章 进程通信
引子:孤独爆破手的自白
6.1 为什么要通信
6.2 进程对白:管道、记名管道、套接字
6.3 进程电报:信号
6.4 进程旗语:信号量
6.5 进程拥抱:共享内存
6.6 信件发送:消息队列
6.7 其他通信机制
思考题
第三篇 线程原理篇
第7章 线程
引子:亚历山大的分身术
7.1 进程的分身术——线程
7.2 线程管理
7.3 线程模型的实现
7.4 现代操作系统的线程实现模型
7.5 多线程的关系
7.6 讨论:从用户态进入内核态
7.7 讨论:线程的困惑——确定性与非确定性
思考题
第8章 线程同步引子:滑铁卢的同步
8.1 为什么要同步
8.2 线程同步的目的
8.3 锁的进化:金鱼生存
8.4 睡觉与叫醒:生产者与消费者问题
8.5 信号量
8.6 锁、睡觉与叫醒、信号量
8.7 管程
8.8 消息传递
8.9 栅栏
思考题
第9章 死锁应对之哲学原理
引子:迷雾笼罩的加拿大
9.1 为什么会发生死锁
9.2 死锁的描述
9.3 死锁的4个必要条件
9.4 哲学家就餐问题
9.5 死锁的应对
9.6 消除死锁的必要条件
9.7 银行家算法:冒险的代价
9.8 哲学家就餐问题之解
9.9 讨论:死锁的思考——综合治理
9.10 讨论:死锁、活锁与饥饿
思考题
第10章 锁的实现
引子:高登绳结
10.1 以中断启用与禁止来实现锁
10.2 以测试与设置指令来实现锁
10.3 以非繁忙等待、中断启用与禁止来实现锁
10.4 以最少繁忙等待、测试与设置来实现锁
10.5 中断禁止、测试与设置
思考题
第四篇 内存原理篇第11章 基本内存管理
引子:让别人无路可走
11.1 内存管理的环境
11.2 内存管理的目标
11.3 虚拟内存的概念
11.4 操作系统在内存中的位置
11.5 单道编程的内存管理
11.6 多道编程的内存管理
11.7 闲置空间管理
思考题
第12章 页式内存管理
引子:虚拟概念的变现
12.1 基址极限管理模式的问题
12.2 分页内存管理
12.3 分页系统的优缺点
12.4 翻译速度
12.5 缺页中断处理
12.6 锁住页面
12.7 页面尺寸
12.8 内存抖动
思考题
第13章 页面更换算法
引子:黑洞理论的替换
13.1 页面需要更换
13.2 页面更换的目标
13.3 随机更换算法
13.4 先进先出算法
13.5 第二次机会算法
13.6 时钟算法
13.7 最优更换算法
13.8 NRU算法
13.9 LRU算法
13.10 工作集算法13.11 工作集时钟算法
13.12 页面替换策略
思考题
第14章 段式内存管理
引子:否定之否定
14.1 分页系统的缺点
14.2 分段管理系统
14.3 分段的优缺点
14.4 段页式内存管理
14.5 段号是否占用寻址字位
14.6 讨论:否定之否定的嵌套——纯粹分段与逻辑分段、分页与段页
思考题
第五篇 文件原理篇
第15章 磁盘操作
引子:EMC——从不可能到可能
15.1 磁盘组织与管理
15.2 磁盘的结构
15.3 盘面的结构
15.4 磁盘驱动器的访问速度
15.5 操作系统界面
15.6 磁盘调度算法
15.7 讨论:固态盘
15.8 讨论:智能磁盘系统
思考题
第16章 文件系统
引子:掩饰的极致
16.1 为什么需要文件系统
16.2 文件系统
16.3 文件系统的目标
16.4 文件的基本知识
16.5 从用户角度看文件系统
16.6 地址独立的实现机制:文件夹
16.7 文件系统调用16.8 内存映射的文件访问
思考题
第17章 文件系统实现
引子:成功中的失败
17.1 文件系统的布局
17.2 文件的实现
17.3 目录实现:地址独立的实现
17.4 闲置空间管理
思考题
第18章 文件系统性能
引子:从不可能到可能
18.1 文件授权管理
18.2 主动控制:访问控制表
18.3 能力表
18.4 访问控制的实施
18.5 其他文件安全措施
18.6 文件系统性能
18.7 文件系统效率性能
18.8 文件系统设计分析:日志结构的文件系统
18.9 海量数据文件系统
思考题
第六篇 1O原理篇
第19章 输入输出
引子:约翰逊的输出——从没有到爆发
19.1 输入输出
19.2 输入输出的目的
19.3 输入输出硬件
19.4 IO软件
19.5 IO软件分层
思考题
第七篇 多核原理篇
第20章 多核结构与内存
引子:不能承受之热20.1 以量取胜
20.2 多核基本概念
20.3 多核的内存结构
20.4 对称多处理器计算机的启动过程
20.5 多处理器之间的通信
20.6 SMP缓存一致性
20.7 多处理器、超线程和多核的比较
思考题
第21章 多核环境下的进程同步与调度
引子:“多核”帝国的陨落
21.1 多核环境下操作系统的修正
21.2 多核环境下的进程同步与调度
21.3 多核进程同步
21.4 硬件原子操作
21.5 总线锁
21.6 多核环境下的软件同步原语
21.7 旋锁
21.8 其他同步原语
21.9 多核环境下的进程调度
21.10 多核环境下的能耗管理
21.11 讨论:多核系统的性能
思考题
第八篇 操作系统设计篇
第22章 操作系统设计之哲学原理
引子:残缺心智的胜利
22.1 操作系统设计的追求
22.2 操作系统设计的第1条哲学原理:层次架构
22.3 操作系统设计的第2条哲学原理:没有对错
22.4 操作系统设计的第3条哲学原理:懒人哲学
22.5 操作系统设计的第4条哲学原理:让困于人
22.6 操作系统设计的第5条哲学原理:留有余地
22.7 操作系统设计的第6条哲学原理:子虚乌有——海市蜃楼之美
22.8 操作系统设计的第7条哲学原理:时空转换——沧海桑田之变22.9 操作系统设计的第8条哲学原理:策机分离与权利分离
22.10 操作系统设计的第9条哲学原理:简单为美——求于至简,归于永恒
22.11 操作系统设计的第10条哲学原理:适可而止
思考题
结语:失望与希望
参考文献前言
In Pursuit of Absolute Simplicity求于至简,归于永恒
当你在电脑上玩游戏、与朋友聊天或编写一个程序并加载运行的时候,你有没有一种像在观看魔术的感觉?
编写好的程序能够编译运行,计算出结果,并显示或打印出来。你有没有觉得它很神秘?
如果想揭开这层神秘的面纱,你就得学习操作系统。
因为操作系统是掌控计算机运行的系统,在学习它的过程中,读者能够了解程序在计算机上运行的全景,或
者说我们所认为的全景(见图1)。之所以这么说,是因为精确了解程序在计算机上运行的全景是极其困难
的(有人认为这根本就是不可能的)。当然,这里的程序指的是有一定规模的程序,而不是那种只有几行代
码的小程序(trivial program)。从某种程度上说,没有人敢肯定自己清楚计算机在任意时刻所处的状态。例
如,在多流水线计算机上,如果发生中断或异常,我们根本就得不到一个精准的状态。唯一能做的就是推倒
重来。
图 1 风靡世界的游戏《第二生命》计算机的心智
人有心智吗?我想所有人都会回答:有!
人的心智就是人的灵气。这是每一个人的生命之气。就是这个灵气赋予了人丰富的思维、感受和行动能力
(当然,也有人认为这是肉体进化的结果,不过这不是本书要讨论的问题)。
那么计算机有心智吗?这不是一个诡秘或者搞笑的问题。
人们通常认为能够运动的生命都是有灵气的,既然计算机能够完成一些人脑才能够完成的理性任务,它当然
也有心智!而这个心智就是操作系统(见图2)。因为操作系统赋予了计算机活力。虽然读者有可能尚不明
白操作系统是怎么一回事儿,但也许知道若没有操作系统,现代计算机是运转不起来的(这里需排除远古时
代的古老计算机)。操作系统作为计算机赖以运转的控制中心,称其为计算机的心智可谓恰如其分。
图 2 计算机的心智就是操作系统
众所周知,理解或看透一个人的心智是很困难的,所谓画虎画皮难画骨,知人知面难知心。依此类推,既然
操作系统是计算机的心智,恐怕理解起来也是困难重重的了。而这正是许多人在学习和研究操作系统时的共
同感受。操作系统的奥秘
记得小时候常常念过的一首诗是这样的:
从小时候就开始数了。
数到懂事、数到成熟,还没有数清。
天上的星星为什么数不清呢?
像记忆和幻想,永远背负着固执的谜……
对于许多大学计算机及相关专业的同学来说,操作系统就像天上的星星(见图3),隐藏着一个固执的谜,永远学不清楚。不过,操作系统真的学不清楚吗?
不是的。学不清楚是因为没有看到其背后的奥秘。这个奥秘不是所有的人都知道的。即使是研究操作系统的
人也不一定意识到它,更别提计算机初学者了。
图 3 理解操作系统有点类似于数清楚天上的星星
那么这个奥秘是什么呢?
天上的星星数不清是因为我们试图做的事情是数星星。如果我们换个角度,不去数星星,而是寻找星星的设
计师,让他告诉我们星星的数量,不就清楚了吗?
这也正是学习操作系统的奥秘。要理解操作系统,就要找到操作系统的设计师,让他们告诉我们操作系统所
蕴涵的所有秘密。当然,这里的寻找设计师并不是真的找来他们,因为找到所有的设计师是不可能的。这里
的设计师指的是一种抽象,一种所有设计师所共有的人生哲学,因为设计师在设计操作系统时会不自觉地将
自己的思维或人生追求构造在操作系统里,从而赋予操作系统以心智,而操作系统也就在这种心智的指挥下
运行着。操作系统之哲学原理
正如前面所述,让设计师告诉我们操作系统的秘密是理解操作系统的最好办法。他们所用的载体就是其所遵
循的生活哲学,这些生活哲学就是操作系统所遵循的哲学原理。
本书就是试图从这些哲学原理(也就是人类生活哲学)的视角来阐述操作系统,从而揭开操作系统的神秘面
纱。
例如,CPU管理(进程与线程)、内存管理(虚拟存储)、外存管理(文件系统)、IO管理(输入与输
出)等操作系统的核心机制不外乎是对资源的管理,它们都遵循着一切人类资源管理的基本原则,即如何有
效地发掘资源、监控资源、分配资源和回收资源。
除了提供管理的功能外,操作系统还需要保证自己的正常运转,即它必须尽力使自身不发生失效或崩溃,因
为这是提供其他一切功能的基础。这与人类确保自身健康生活作为开发利用资源的前提是一个道理。
如果我们掌握了资源的根本属性,即资源管理必然涉及共享和竞争的管理,理解了操作系统必须首先保障自
己的正常运转,就会理解操作系统的一切行为。前者指引着操作系统功能的设计与进化,后者则推动着操作
系统可靠性的演变。
资源管理也好,保证自身的正确性也好,它们都存在着根本的线索。这条根本线索就是人类在长期的生活实
践中摸索出来的管理社会和保障自身安全的各种办法。这些办法是随着人类哲学思维的变化而改进的。因
此,只要明白了人类的哲学思维,就能明白操作系统所遵循的哲学原理,进而明白整个操作系统的设计与构
造。
除了使操作系统易于理解外,从哲学的层面阐述操作系统的原理还有如下好处:
●操作系统可以变化,但支持其存在的哲学原理是不变的。这样,本书的内容可以在操作系统不断演变的环
境下保持有效,而不会像其他书中的内容,随着时间的推移而过时。
●对于很多人来说,操作系统所采取的机制、策略和手段看上去十分枯燥,如果从哲学原理上给它们赋予人
性的特点,这些机制、策略和手段便不再枯燥。
通过将人生哲学与操作系统结合起来,从操作系统哲学原理的层次阐述操作系统的核心技术,就能够理解和
掌握操作系统的精髓。本书内容安排
为清楚地阐述操作系统的哲学原理,也为了使内容显得紧凑,逻辑上一气呵成,本书只选择了操作系统的核
心内容进行分析,放弃了对操作系统核心以外内容,如安全、多媒体系统、虚拟机技术、光盘技术等的论
述。本书集中精力对操作系统发展的历史背景、进程与线程、内存管理、文件系统、输入与输出、多核环境
下的进程调度和操作系统设计进行了哲学原理层面上的分析与论述,而将安全、多媒体、虚拟机等技术留给
别的专业书籍进行论述。对内容的这种安排有如下好处:
●可使本书重点突出、逻辑清晰、内容连贯,便于学生顺利掌握操作系统的核心与关键。
●操作系统的核心内容经过长久的研究与实践,已经变得较为稳定并且形成了众所公认的标准,讲解起来没
有歧义。
●操作系统的非核心部分由于研究的时间短,工业界参与的程度较低,并无公认的标准,论述起来要么不全
面,要么显得凌乱,使刚刚接触操作系统的读者感到迷惑。
●只要掌握了核心内容的原理,读者便能通过自学掌握操作系统核心以外的知识。
本书覆盖全国硕士研究生入学统一考试计算机学科《研究生考试大纲》中操作系统部分全部内容。
本书分为8篇,分别是基础原理篇、进程原理篇、线程原理篇、内存原理篇、文件原理篇、IO原理篇、多核
原理篇和操作系统设计篇,内容结构如图4所示。
图 4 本书内容结构
基础原理篇
该篇包含第1~3章的内容。第1章的内容包括智者的挑战、人造与神造、程序是如何运行的、什么是操作系
统、魔术与管理、用户程序与操作系统、操作系统范畴和为什么学习操作系统。第2章探讨操作系统演变的
主要过程:从单一控制终端、单一操作员,到批处理、多道批处理、分时操作系统、实时操作系统、现代操
作系统;对商业操作系统演变的过程进行了分析,然后探讨操作系统的分类和未来发展趋势。第3章简要回
顾计算机硬件基本知识,探讨什么是“抽象”,讲解用户态与内核态,阐述操作系统结构、系统调用、操作系
统的壳等知识。
进程原理篇
该篇对操作系统最核心的概念——进程进行讲解,包括第4~6章的内容。第4章阐述进程出现的逻辑必然
性、多道编程的效率、进程的创建和消亡、进程的状态及其转换、进程与地址空间、进程模型的实现和进程
模型的缺陷。第5章讲解进程模型实现的手段:调度,主要内容包括调度的目标,先来先服务、时间片轮
转、短任务优先、优先级调度、混合调度、实时调度等算法,并对优先级倒挂和线程的不确定性进行讨论。
第6章的内容包括为什么要通信、管道、记名管道、套接字、信号、信号量、共享内存、消息队列等。线程原理篇
进程虽然让并发从理想变为现实,但其自身却是串行的:进程只有一个执行序列。若要使进程本身也提供并
发,则需要对线程进行讨论。该篇讨论了进程级的并发机制-线程模型,包括第7~10章的内容。第7章的内
容包括进程分身术——线程、线程管理、线程的用户态和内核态以及混合态实现、现代操作系统的线程实现
模型、多线程之间的关系、线程模型主要考虑的问题等。第8章的内容包括为什么同步、同步的目的、锁原
语的进化、睡觉与叫醒原语、信号量、管程、消息传递和栅栏等。第9章对死锁的产生、发展、防止与避免
进行讲解,并讨论死锁、活锁和饥饿的关系。第10章讲述如何使用中断启用和禁止、测试与设置来实现锁原
语。
内存原理篇
该篇对操作系统的另外一个重要构成部分——内存管理进行阐述,包括第11~14章的内容。第11章讲述内存
管理的环境、内存管理的目标、虚拟内存、操作系统在内存中的位置、单道编程的内存管理、固定加载地
址、多道编程的内存管理、固定分区、非固定分区、交换、地址翻译、闲置空间管理等内容。第12章讲解的
内容包括基址极限的问题、分页管理、页表、页面翻译过程、分页管理系统的优缺点、多级页表、地址翻译
速度、锁住页面、内存抖动和页面尺寸设计。第13章对页面更换算法的来龙去脉、欲达到的目的、各种具体
的页面更换算法进行细致讲解。第14章的内容包括分段管理系统、分段的优缺点、段号与寻址位数,并对否
定之否定在内存管理模式发展过程中的作用进行了讨论。
文件原理篇
该篇对操作系统的第三个核心构件——文件系统进行讲解。包括第15~18章的内容。第15章讲述的内容包括
磁盘结构、磁盘访问速度、磁盘的操作系统界面、磁盘访问过程和磁盘调度。第16章讲述为什么需要文件系
统、什么是文件系统、文件系统的目的、文件的基本知识、文件的存储结构、文件类型、文件访问、文件属
性、文件操作、文件夹、相对与绝对路径、共享与链接、内存映射的文件等内容。第17章的内容包括文件系
统分布、文件的实现、文件夹的实现、共享文件的实现、磁盘空间的管理等。第18章的内容包括文件安全性
能(文件访问控制、访问控制表、能力表)、文件可靠性能(持久性、一致性、日志、交易、随影、一致性
检查)和文件系统的效率性能(提前读取、减少磁臂移动距离、日志结构的文件系统LFS)。
IO原理篇
该篇对计算机与外界进行沟通的机制——输入与输出进行讲解。该篇仅有一章(第19章),讨论的内容包括
输入输出的重要性和目的、输入输出硬件的哲学原理、物理IO模式(专有通道IO、内存映射的IO、复合
IO、DMA)、输入输出软件的哲学原理、软件IO模式(可编程IO、中断驱动的IO、DMA)、IO软件分
层和设备驱动程序等。
多核原理篇
该篇对新出现的多核技术进行讲解,重点讨论多核环境给操作系统带来的影响。该篇分为多核结构和多核环
境下的进程同步与调度两章。第20章讲解的内容包括多核处理器结构(超线程结构、多核结构、多核超线程
结构)、多核内存结构(UMA、NUMA、COMA、NORMA)、对称多核处理器计算机的启动过程、多处
理器之间的通信、SMP缓存一致性等。第21章的内容包括多核进程同步、多核环境下的软件同步原语、旋锁
及其实现、队列旋锁、多核环境下的进程调度、多核环境下的能耗管理和多核系统性能。
操作系统设计篇
该篇从高屋建瓴的角度对操作系统设计的十条哲学原理进行阐述。显然,操作系统的设计原则有很多,本篇
选取的只是诸多原则里面非常重要的十条。第22章将从操作系统和人类社会两个层面对这十条原理进行论述
与比较,以使读者更加清楚地明白操作系统就是人类社会在计算机里面的反映。读者可自行发现操作系统的
其他设计原则。本书特点
本书从哲学的视角对操作系统阐述了独到的见解。从人类自然的行为规范推演到操作系统的设计,以一条逻
辑主线演绎了整个操作系统的各种原理。本书的特点是抽象提升(即从哲学原理上阐述操作系统的各种原理
与设计)、联系生活(即通过人所熟知的生活实例来分析操作系统)、模块整合(即将操作系统的各个模块
通过举例连结起来)、逻辑贯通(即将操作系统的各种机制以一根逻辑主线的发展依次讲解)和系统关联
(即将涉及的其他学科知识点如体系结构和编译器等嵌入进来)。本书内容上更加新颖、系统上更加完整、逻辑上更加连贯、解说上更加易懂和层次上更加丰富的特点。
读者在阅读学习完本书后,将达到如下目标:
★了解操作系统在计算机软硬件整个体系中的中心主导作用。
★掌握操作系统的基本概念、原理、技术和实现机制。
★理解操作系统原理背后的人文背景与历史动机。
★运用操作系统知识来分析和解决问题。
★掌握操作系统设计的原理,为以后设计操作系统打下基础。
这里需要提醒的是,本书阐述的是操作系统的原理,它不依赖于任何具体的实现,而是凌驾于所有具体商业
操作系统的进程实现之上,即本书所阐述的思想和原理对所有操作系统都适用。但具体商业操作系统在应用
这些原理时可以有很灵活的方式。事实上,具体的商业操作系统在应用这些原理时确实采取了不同的方式,有的更为精密,也有的更加精简。另外,由于我们注重的是原理,对个体机制实现时采取的数据结构通常不
做详细的论述,而是点到为止。这是因为数据结构必须以真正的操作系统为蓝本进行讲解,而真正的商业操
作系统使用的数据结构通常非常复杂,对此进行繁琐的讲解将把学生弄得晕头转向,而不利于对操作系统核
心原理的把握。
当然了,如果要达到能够设计开发真正商业操作系统的境界,读者还需要进行“操作系统工程”或“操作系统
实现”等知识的学习。而这种工程或实现的课程通常以具体的操作系统为对象进行讲述。这些具体操作系统
可以是Windows、UNIX、Linux,当然也可以是其他一些非主流商业操作系统(如Android、Symbian等)。
如果能够将本书阐述的原理与操作系统工程或实现相结合,将取得极好的效果。
此外,本书使用的伪代码采用类似CC++的结构,每种原理的表示均以展示操作系统的思路为最高目标,并
不对表示的细节进行优化,以使得逻辑清晰,方便绝大多数读者理解。
现在就让我们一起来揭示秘密,数清操作系统里的星星吧。第一篇 基础原理篇
大伪似真,大道无形
对于任何一门课来说,首要探讨的问题就是这门课的主题到底是什么。对于刚接触操作系统的入门者来说,自然想到的问题当然也会是操作系统到底是什么东西。回答这个问题是本篇的职责。此外,操作系统作为计
算机的核心控制系统,它在计算机运行过程中扮演什么角色?它的来历是什么?它有一些什么基本概念?我
们应该如何看待操作系统?它是如何参与到程序的执行过程中的?这些也是学习操作系统需要回答的基本问
题。
本篇就是针对上述问题而写成。它对这些问题进行解答和讨论,并为我们接下来介绍操作系统的核心功能部
件打下基础和铺垫。本篇包含第1~3章的内容。第1章的内容包括智者的挑战、人造与神造、程序是如何运
行的、什么是操作系统、魔术与管理、用户程序与操作系统、操作系统范畴和为什么学习操作系统。第2章
探讨操作系统演变的主要过程:从单一操作员单一控制终端,到批处理、多道批处理、分时操作系统、实时
操作系统、现代操作系统;对商业操作系统演变的过程进行了分析,然后探讨操作系统的分类和未来发展趋
势。第3章简要回顾计算机硬件基本知识,探讨什么是“抽象”,讲解用户态与内核态,阐述操作系统结构、系统调用、操作系统的壳等知识。
本篇最为重要的核心思想是操作系统在计算机运行过程中扮演的角色:魔术师和管理者。魔术师将丑陋变得
美好,将没有变为有,将少变为多;而管理者则对所有计算机资源进行管理以达到公平和效率的“双料”境
界。对操作系统这两个角色的理解将非常有助于对进程、线程、虚拟内存、文件系统和输入输出系统的掌
握。
化丑为美:魔术师是操作系统扮演的一个根本角色第1章 操作系统导论
引子:智者的挑战
西方有一个著名的故事,名曰:智者的挑战。相传很久以前,有个村子里住着一位智者。同村有个年轻人学
到一些知识后就想来挑战这位智者。于是,年轻人想到了一个方法。他来到智者面前,将双手放在背后,问
这个智者:
“我刚刚从树上抓了只鸟,现在我手中。但你能告诉我,这只鸟是活的还是死的呢?”
这是一个诡诈的问题。因为,如果回答“是活的”,则这个年轻人只需要在背后将鸟掐死,然后给智者看这只
死鸟;如果回答“是死的”,则这个年轻人只需要将鸟放飞即可。这样,无论智者如何回答,年轻人都可以让
智者答错,然后可以大大地嘲笑一番智者的水平。
作为智者,当然一眼就看出了年轻人的诡计。但是又不能不回答这个问题。因为不回答问题等于承认答不上
来,当然也就是不是什么智者了。但如何回答呢?
智者的回答简洁、精妙,甚至妙不可言:As you will。
will这个词在英语中的意思是意愿或意志。因此这个答案的意思是:这只鸟的死活与年轻人的意志保持一
致:年轻人的意志是让这只鸟活,则这只鸟就是活的;年轻人的意志是让这只鸟死,则这只鸟就是死的。
如果到此止步,则这个答案仍存在着巨大的漏洞:年轻人可以将鸟掐死,但坚持说自己的意志是让鸟活着,即自己不小心将鸟掐死了,而自己的意志却是想让鸟活着。若是这样的话,智者的回答就错了。
妙不可言的是,will在英语中还有一层意思:将要,即将要发生的事或将要采取的行动。就是说,这只鸟的
死活与年轻人将要采取的行动保持一致:年轻人将要放飞这只鸟,则这只鸟就是活的;年轻人将要掐死这只
鸟,则这只鸟就是死的。
因此,智者的回答将人的意志与行为全部包括了进来。这样,即使年轻人声称他的意愿和行为并不一致,智
者的回答也正确无误。
好,我们知道了智者的回答。但这与操作系统课程有什么关系吗?
有!很多人都觉得操作系统枯燥、乏味,甚至令人厌烦。更有人说懂不懂操作系统没有关系。不是很多人在
学习操作系统之前就已经写过程序了吗?有的人甚至已经写过很大很复杂的程序了。可见,不懂操作系统并
不妨碍我们学习使用计算机。
如果读者这样想,我劝你再想一想。你虽然写过程序,可你知道程序到底是如何在计算机上运行的吗?如果
不知道,你怎么敢肯定你的程序总会运行正确呢?你怎么敢说你写的程序最大限度地利用了系统的能力呢?
一个人觉得操作系统没用,那是因为他不知道怎么用,或者他没有用操作系统的意愿。说明白一点,如果你
认为操作系统没有用,那是因为你的编程和程序开发处在一个低级的水平上。如果你掌握了操作系统,你的
编程水平将显著提高。
换句话说,操作系统有没有用,我的回答是As you will。你如果有意愿或者有行动使用操作系统,操作系
统就是有用的;如果你没有意愿或行动,则操作系统就是没有用的。当然了,我希望读者在看完这本书后能
够领悟到操作系统的巨大用途。万一在读完本书后,读者还感觉困惑或者认为操作系统没用,我唯一能说的
也是As you will了。当然,我希望这种情况发生的概率不大。1.1 人造与神造
要想学好操作系统,具有恰当的思维模式是十分必要的。这个思维模式就是本书所强调的“哲学”:一种思维
方式或一种生活方式。我们以一个问题来说明这一点。这个问题是:
“什么是计算机的根本特征?”
对于这个问题,相信很多人会说计算机就是台计算机器,或者用来进行大规模计算的机器,或者用于数据处
理的机器,或者具备某些其他具体功能的机器。这些回答当然没有错,问题是这些答案并不能帮助我们更好
地学习和理解计算机。就像我们问“张三这个人的根本特征是什么”,而回答却是“张三有175cm高”一样。这
种答案虽然是正确的,但意义不大,因为我们无法从答案中推导出一系列有用的结论。
那这个问题该如何回答呢?这就要看我们对事物的观察程度了。如果我们仔细看看身边的事物,就会发现所
有的东西可以划分为两类:一类是本来就存在于自然中,人类所做的只不过是发现;另一类是本来并不存
在,人类所做的是发明。前者称为神造事物或者自然存在的事物,后者当然就是人造事物。从这个思维模式
上看,计算机毫无疑问就是人造事物。这正是我们所需要的答案,即计算机的根本特征是“人造”。
引申一下可知,计算机学科就是一个人造学科。那么知道计算机学科是人造学科对我们学习计算机有什么帮
助呢?有,太多了。下面我们来看看人造和神造有什么区别。
人造学科的四个特点:
●不精确、具有相对性。
●从对人类活动的观察导出。
●依赖于人的主观判断力。
●通常符合人的直觉。
第一个特点就是所谓的“没有对错”。在人造学科里,没有什么绝对的对或错,而只有所谓
的“好”或“坏”,“有意义”或“没意义”。例如,如果本书在讨论计算机时对某个方面的论述与你见到的计算机
不一样,这并不能说明本书错了。就算世界上不存在本书所论述的计算机,也不能说明本书错了。我们只需
要按照本书的论述再造一台计算机即可。但是,本书论述的计算机与你知道的计算机之间可以进行好和坏的
比较。
第二个特点说的是人造学科是从哪里得到灵感的,那就是“对人类活动的观察”。这样,读者只要对人类生活
仔细观察,就可以很容易地理解计算机里面的许多原理。例如,在操作系统里面广泛使用的栈和队列就是对
从生活中观察到的现象进行抽象所获得,如图1-1所示。
图 1-1 从观察人类活动而获得的栈和队列结构
第三个特点说的是在人造学科里,人的主观能动性起着关键作用。不同的人观察同样的现象,得出的结论或
抽象出的东西可能不一样,甚至完全相反。这样,多数人所认同的抽象就将成为人造学科里的标准,即存在少数服从多数的原则。
第四个特点说的是人造学科里面的许多原理与人的直觉直接呼应,即如果我们按照人的直觉去理解这些原
理,就会十分直截了当。例如,操作系统里面的同步机制与人类男女谈恋爱时所用的约会机制十分相似。对
于一个谈过恋爱或与别人约会过的人来说,如果将自己谈恋爱的直觉用在操作系统进程的学习上,就会发现
进程同步是个十分容易理解的概念。
相对人造学科,自然存在或神造学科刚好具有相反的四个属性:
●精确、绝对。
●从对自然存在的观察导出。
●不依赖于人的主观判断力。
●通常违反人的直觉。
第一个特点说的是神造的事物具有精确、绝对的属性。对于这种学科,存在正确与错误之分,我们提出的观
点要么正确,要么错误,不存在中间状态。例如,纯数学领域的各种运算,如22的结果应该是4。如果运算
的结果不是4,则属于运算错误。
第二个特点说的是人类对这些事物的理解是从对自然存在的观察中获得。例如,牛顿通过观察苹果落地的自
然现象和严密的推理,得出了万有引力定律。
第三个特点说的是这些观察的结果是不依赖于人的主观能动性的。如果一个人的观察结果是正确的话,那么
他的观察将和所有观察正确的人的结果一样,而绝不会是两样。从另外一个角度说,一个人的观察抽象结果
是可以被他人验证的。例如,30 000 000 000+20 000 000 000对于任何人来说,如果计算正确,则结果必然
是50 000 000 000。
第四个特点说的是如果我们按照人的直觉来学习,就会面临重重困难。因为人的思维与神不一样。自然,按
照人的思维模式将很难理解神所创造的这一切。这就是为什么在这些学科耕耘的人都必须依赖灵感的出现,以及严密、一丝不苟的数学与逻辑推理(见图1-2)。
明白了计算机是人造事物,操作系统是一个人造系统,我们就可以按照人造事物的特点来学习,从而易如反
掌地掌握操作系统的原理。
图 1-2 从观察自然存在和严密的数学推理而获得的质能方程1.2 程序是如何运行的
计算机程序是如何运行的呢?对于多数人来说,或多或少地知道任何程序必须首先得有人写出来,即编程,然后放到计算机运行。这种解释当然是过于简单了。计算机程序的运行实际上是一件十分复杂的事情,牵扯
到方方面面。
首先,当然得进行编程,而编程需要计算机程序设计语言作为基础。对于绝大多数编写程序的人来说,使用
的编程语言称为高级程序设计语言,如C、C++、Java等。但由于计算机并不认识高级语言编写的程序,编
好的程序需要进行编译变成计算机能够识别的机器语言程序,而这需要编译器和汇编器的帮助。其次,机器
语言程序需要加载到内存,形成一个运动中的程序,即进程,而这需要操作系统的帮助。进程需要在计算机
芯片CPU上执行才算是真正在执行,而将进程调度到CPU上运行也由操作系统完成。最后,在CPU上执行的
机器语言指令需要变成能够在一个个时钟脉冲里执行的基本操作,这需要指令集结构和计算机硬件的支持,而整个程序的执行过程还需要操作系统提供的服务和程序语言提供的执行环境(runtime environment)。这
样,一个从程序到微指令执行的过程就完成了。图1-3所示的就是这个过程。
当然了,图1-3描述的从程序到结果的演变过程还是过于简单。我们只是从一个线性角度来看程序的演变过
程,而没有考虑各种因素之间的穿插和交互过程。不过,对于刚入门的计算机专业学生来说,这种描述能够
帮助理解整个程序是如何在计算机上执行的问题。
图 1-3 由程序到结果的演变
从这个描述中可以看出:程序的运行至少需要如下四个因素:
●程序设计语言。
●编译系统。
●操作系统。
●指令集结构(计算机硬件系统)。这四个因素都将是大学学习的专业课程。需要注意的是,操作系统在程序的执行过程中具有关键的作用,本
书要做的就是阐述这个关键作用是如何发挥的。
需要注意的是,图1-3给出的程序执行过程是从高级语言编写的程序开始的。而实际上并非总是这样。事实
上,程序可以直接在机器语言或汇编语言上编写。用这种称为“低级”的语言编写出来的机器语言程序无需经
过编译器的翻译就可以在计算机指令集上执行。如果是在汇编语言上编写的汇编程序,则只需要经过汇编器
的翻译即可加载执行。1.3 什么是操作系统
操作系统这个术语听上去稀松平常,并不给人任何兴奋的感觉,甚至有点俗气。原因在于中文的“操作”这个
词:提到操作员,通常让人想起操作车床、磨床和起重机的穿着油腻工作服的工人,这自然让人兴奋不起
来。将英文的operating翻译为中文的“操作”,是因为翻译的人没有理解英文Operating Systems(OS,操作系
统)这个名字所蕴涵的精髓。
那么英文的Operating Systems意味着什么呢?
各位见过手术过程吗?在手术室里,主刀大夫称为Operating Surgeon。在整个手术过程中,主刀大夫具有至
高无上的权威:他说要打麻药,麻醉师便要赶紧打麻药;他说需要手术钳,助理大夫就赶忙递给他手术钳;
他说需要止血,护士就要忙不迭地拿止血药棉来止血。整个手术最关键的部分,切开皮肤、拿掉器官、安装
移植器官等均由主刀大夫完成。当然,主刀大夫有时候也会将某些任务,如缝合创口,交给助理大夫或护士
来做,但整个手术的过程皆由其主控。一句话,Operating Surgeon就是掌控整个手术过程、具有精湛技术和
敏锐判断力的医师。
引申至非医学领域,Operating Person意思是操刀手,就是掌控事情的人。再将Person这个词换成System,则
Operating Systems指的就是掌控局势的一种系统。也就是说计算机里面的一切事情均由Operating Systems来
掌控。那么,我们现在面临两个问题:第一个问题是,操作系统到底是什么东西?第二个问题是,操作系统
到底操控什么事情?
我们先回答第一个问题。既然操作系统是掌控计算机局势的一个系统,自然很重要。但这个说法并不能帮助
读者理解操作系统,也无法形成有形的概念。如果我们换个说法:操作系统是介于计算机和应用软件之间的
一个软件系统,则概念就具体多了。从这个定义出发,我们知道操作系统的上面和下面都有别的对象存在:
下面是硬件平台,上面是应用软件,如图1-4所示。
图 1-4 操作系统上下界面
现在回答第二个问题。我们知道操作系统代表的是掌控事情的系统,掌控什么事情呢?当然是计算机上或计
算机里发生的一切事情。最原始的计算机并没有操作系统,而是直接由人来掌控事情,即所谓的单一控制终
端、单一操作员模式。但是随着计算机复杂性的增长,人已经不能胜任直接掌控计算机了。于是我们编写出
操作系统这个“软件”来掌控计算机,将人类从日益复杂的掌控任务中解脱出来。这个掌控有着多层深远的意
义。
首先,由于计算机的功能和复杂性不断发生变化(趋向更加复杂),操作系统所掌控的事情也就越来越多,越来越复杂。同时,操作系统本身能够使用的资源也不断增多(如内存容量)。这是早期驱动操作系统不断
改善的根本原因。
其次,既然操作系统是专门掌控计算机的,那么计算机上发生的所有事情自然需要操作系统的知晓和许可,未经操作系统同意的任何事情均视为非法的,也就是病毒和入侵攻击所试图运作的事情。作为操作系统的设
计人员,我们当然要确保计算机不发生任何我们不知情或不同意的事情。但是人的能力是有限的,人的思维
也是有缺陷的,我们设计出的系统自然不会十全十美,也会有缺陷,这就给了攻击者可乘之机。操作系统设
计人员和攻击者之间的博弈是当前驱动操作系统改善的一个重要动力。
再次,掌控事情的水平有高低之分,有效率不同之分。就像手术大夫之间也有水平高低之分。为了更好地掌
控事情,同时也为了更好地满足人类永不知足的各种越来越苛刻的要求,操作系统自然需要不断改善。这种
改善在过去、现在和将来都会继续下去的。最后,我们可以给操作系统下定义了:
●操作系统是一个软件系统;
●操作系统使计算机变得好用(将人类从繁琐、复杂的对机器掌控的任务中解脱);
●操作系统使计算机运作变得有序(操作系统掌控计算机上所有的事情)。总结起来就是:操作系统是掌控
计算机上所有事情的软件系统。
从这个定义可以引申出操作系统的功能:
●替用户及其应用管理计算机上的软硬件资源。
●保证计算机资源的公平竞争和使用。
●防止对计算机资源的非法侵占和使用。
●保证操作系统自身正常运转。1.4 魔术与管理
提升上面所列的操作系统功能,可以得出操作系统所扮演的两个根本角色:管理者和魔术家。只要记住了这
两个角色,就差不多明白了什么是操作系统。
1.4.1 魔术家角色
魔术家的目标是把差的东西变好,把少的东西变多,把复杂变简单。同样,操作系统将计算机以一个更加容
易、更加方便、更加强大的方式呈现给用户。例如,如果在裸机上直接编程是很困难的,因为各种数据转移
均需要用户自己来控制,对不同设备要用不同命令来驱动,而这对一般人很难胜任。操作系统将这些工作从
用户手中接过来,从而让用户感觉编程是一件容易的事(相对来说,编程对于有些人来说永远很难),如图
1-5所示。
操作系统通过进程抽象让每一个用户感觉有一台自己独享的CPU;通过虚拟内存抽象,让用户感觉物理内存
空间具有无限扩张性,这就是把少变多。当然,操作系统的把少变多不是无中生有,变多也不是无限多,只
是针对磁盘容量的大小。1.4.2 管理者角色
操作系统管理计算机上软硬件资源。例如,操作系统对CPU、内存、磁盘等的管理,使得不同用户之间或者
同一用户的不同程序之间可以安全有序地共享这些硬件资源。那怎么让用户很好地利用这些硬件资源呢?就
是分块(parcel out),把硬件分块给应用程序使用。这里关键的原则是有效和公平,这是管理者的必备素
质。有效指的是不能浪费资源,公平指的是每个人都有可能享有资源,即不能有不公平的现象。当然真正的
公平是没有的事,这很像人类生活的现实。不过追求公平却是我们的本能,在虚拟世界里尽可能公平一点还
是非常应该的,至少应该是设计操作系统时的不懈追求。
图 1-5 操作系统就是一个魔术师(illusionist)
根据管理的资源不同,操作系统具体功能如下:
●CPU管理,即如何分配CPU给不同应用和用户。
●内存管理:即如何分配内存给不同应用和用户。
●外存管理:即如何分配外存(磁盘)给不同应用和用户。
●IO管理:即如何分配输入输出设备给应用和用户。
除了对上述资源进行管理和抽象外,操作系统作为掌控一切的软件系统,其自身必须是稳定和安全的,即操
作系统自己不能出现故障。因此,操作系统的设计还需包括如下两项:
●健壮性管理:即如何确保操作系统自身的正常运作。
●安全性管理:即如何防止非法操作和入侵。
为完成上面所列的功能,操作系统设计人员构思了许多机制。而所有这些机制均有其渊源,其背后隐含的是
人的哲学思维。本书就是要讲解操作系统背后的哲学原理,并依据这些哲学原理阐述操作系统是通过何种机
制、以何种方式完成上述列举的各种管理功能的。1.5 用户程序与操作系统
前面说过,操作系统上下分别是虚拟机器界面和物理机器界面。处于物理机器下面的是硬件,而硬件和操作
系统的关系将是本书的关注点。处于虚拟机器界面上面的是应用软件,应用软件和操作系统的关系不是本书
的重点,而是系统编程或底层编程等课程的关注点。在这里,我们只想来简要讨论一下应用程序和操作系统
的关系,因为这个关系对理解操作系统非常重要。
那么,操作系统和应用程序之间是什么关系呢?很显然,操作系统为用户程序提供了一个虚拟机器界面,而
应用程序运行在这个界面之上。但这个答案似乎太抽象,并不能帮助深入理解它们之间的关系。前面讲过,操作系统是一个程序,而用户程序也是程序,程序和程序之间能有什么关系呢?无非是调用和被调用的关
系。
那操作系统和用户程序之间到底谁是调用者,谁是被调用者呢?答案似乎很清楚:操作系统通过虚拟机器界
面为用户程序提供各种服务,用户程序在运行过程中不断使用操作系统提供的服务来完成自己的任务。例
如,用户程序在运行过程中需要读写磁盘,这个时候就需要调用操作系统的服务来完成磁盘读写操作;如果
需要收发数据包,也需要调用操作系统的服务来完成。当调用这些服务时,控制从用户程序转移到操作系
统,而操作系统在完成这些服务后将控制返回给用户程序。在这种思维模式下,用户程序是主程序,而操作
系统是子程序,如图1-6所示。
图 1-6 用户程序为主程序,操作系统为子程序
但是有正就有反,这就是哲学中的矛盾论。如果我们从另一个角度来看,会得出相反的结论。系统启动之后
最先启动的是什么程序?操作系统。用户程序不能在操作系统启用之前启动(除非是很厉害的病毒)。在此
之后,每次启动一个用户程序,都相当于操作系统将控制转移给用户程序;而在用户程序执行完毕后,控制
又回到操作系统。这样看上去,操作系统是主程序,它在一生当中不断调用各种应用程序,而每个应用程序
执行完之后再回到操作系统。就这样循环往复,直到无穷或机器关闭。在此种思维模式下,操作系统是主程
序,用户程序是子程序,如图1-7所示。
上述两种看法完全相反,但又似乎都有道理,有谁对谁错之分吗?没有。我们说过,人造学科没有对错之
分,只有好坏之分。你喜欢哪种观点就持那种观点,哪种观点帮助你理解操作系统,你就持那种观点。如果
两种观点都有帮助,你可同时持有两种观点。图 1-7 操作系统为主程序,用户程序为子程序
当然,上述关系的描述是非常简单化的。实际上,操作系统和各种用户程序可以看做互相调用,从而形成一
个非常复杂的动态关系。了解并阐述这种复杂的动态关系就是本书的目的。1.6 操作系统的范畴
前面介绍了操作系统的两个角色:魔术师和管理者。这两个角色之间既有区别,又有联系。为了完成不同的
任务,操作系统有时需要扮演魔术师的角色,有时需要扮演管理者的角色,有时则需要同时扮演这两个角
色。那么操作系统要完成的任务具体有哪些呢?前面提到过:
●CPU管理,即如何分配CPU给不同应用和用户。
●内存管理:即如何分配内存给不同应用和用户。
●外存管理:即如何分配外存(磁盘)给不同应用和用户。
●IO管理:即如何分配输入输出设备给应用和用户。
CPU管理就是将要介绍的进程管理。进程管理的主要目的有3个:第一个是公平,即每个程序都有机会使用
CPU。第二个是非阻塞(non-blocking),即任何程序不能无休止地阻挠其他程序的正常推进。如果一个程
序在运行过程中需要输入输出或者因别的什么事情而发生阻塞,这个阻塞不能妨碍别的进程继续前进。就像
人类世界,缺了谁地球照样旋转。第三个是优先级。在人类生活中人的地位不完全一样,地位高的就比地位
低的优先级高。人类把自己生活中的这种关系搬到操作系统里面,就有了优先级的概念,即某些程序比另外
一些程序优先级高。如果优先级高的程序开始运行,则优先级低的程序就要让出资源。就像我们经常说的,我们坚决反对大锅饭,应该让一部分人(程序)先富起来。
内存管理主要是管理缓存、主存、磁盘、磁带等存储介质所形成的内存架构。为此目的,操作系统设计人员
发明了虚拟内存的概念,即将物理内存(缓存和主存)扩充到外部存储介质(磁盘、光盘和磁带)上。这样
内存的空间就大大地增加了,能够运行的程序的大小也大大地增加了。内存管理的另一个目的是让很多程序
共享同一个物理内存。这就需要对物理内存进行分割和保护,不让一个程序访问另一个程序所占的内存空
间,专业术语称为运行时不能越界。在生活中,就是我家的东西不希望你跑来拿。
外存管理通常也称为存储管理,它就是众所周知的文件系统了。文件系统的主要目的是将磁盘变成一个很容
易使用的存储媒介以提供给用户使用。这样我们在访问磁盘时无须了解磁盘的物理属性或数据在磁盘上的精
确位置,诸如磁道、磁柱、扇面等。当然,文件系统还可以建立在光盘和磁带上。只是使用最为频繁的文件
系统都以磁盘为介质。
IO管理也称为设备管理,就是管理输入输出设备。IO管理的目的有两个:一是屏蔽不同设备的差异性,即
用户用同样的方式访问不同的设备,从而降低编程的难度;二是提供并发访问,即将那些看上去并不具备共
享特性的设备(如打印机)变得可以共享。
另外还有一个任务称为批处理,它提供一种无需人机交互的程序运行模式。有时我们不需要人来交互,就交
给计算机批处理。主要目的是达到吞吐量最大化,单位时间完成的任务最多。图1-8描述的是操作系统的5个
核心功能。
当然,在真实的操作系统里,上述5个核心部件不一定界限分明,甚至它们不在同一个态势下运行(本书后
面将说明这一点)。图1-9描述的是Windows操作系统简化了的结构。
图 1-8 操作系统的5个核心功能图 1-9 Windows操作系统简化结构图1.7 为什么学习操作系统
到目前为止,本书论述了操作系统的定义、主要任务以及操作系统与用户程序的关系,读者可以体会到操作
系统的重要性。但仅仅是因为操作系统重要就要学习它吗?世界上重要的东西太多了,难道我们都要学吗?
即使是计算机专业的学生,不学操作系统也照样可以编程写软件。那我们为什么要学呢?当然我们有一千个
理由要学,但这里仅列出了几个。
首先,操作系统的功能应用于很多领域。如果开发并发程序:Web Service、分布式系统和网络,你会发
现,这些领域大量使用了操作系统的概念和技术。如果你学好了操作系统,你就可以对你做的事情更加有信
心。
其次,操作系统的技巧也应用于很多领域,如抽象、缓存、并发等。操作系统简单来说就是实现抽象:进程
抽象、文件抽象、虚拟存储抽象等。而很多领域也使用抽象。如数据结构和程序设计就大量使用了抽象,记
得抽象数据类型吗?记得抽象类吗?很多地方都用缓存。你开发Web应用要不要缓存呢?这些你都需要。如
果学习操作系统,你就掌握了这些知识。触类旁通,你学习别的知识时就容易多了。
不过最重要的理由并不是上面的两条,而是操作系统真的很有趣。对于一个计算机专业的学生来说,难道不
想知道自己写的程序如何在计算机上运行吗?读者一定见过汽车吧。汽车前面那个盖子叫前盖(hood)。很
多人买车后第一件事是什么?打开前盖。那么打开前盖看到的是什么东西?马达、变速箱。为什么第一件事
要打开前盖呢?因为好奇这辆汽车是怎么开动的(见图1-10)。
图 1-10 学习操作系统就是揭开覆盖在计算机上的“前盖”
那么对于一个程序员来说,有没有在看到一台计算机的时候,想过为什么计算机能进行计算?有没有买来一
台新计算机后就打开盖子呢?多数人恐怕没有打开过计算机外壳。不过,没有打开过也不用遗憾。因为即使
你把计算机后盖打开,还是不能明白计算机是怎么运转的,此时只看到一堆硬件:芯片、主板、布线等,而
这些硬件并不会告诉你太多有关计算机运转的信息。如果真的想知道计算机是怎么运转的,你就得学习操作
系统。当然,如果你想知道计算机在硬件层面上是如何运转的,则还应该学习计算机组成和体系结构等课
程。
虽然学习操作系统很有趣,但并不是所有人都有这样的感觉。历史证明,对很多人来说,学习操作系统是一
件很痛苦的事情。不过我希望阅读本书对读者来说是一件乐事,难道窥探奥秘不是一件激动人心的事吗?思考题
1.什么是操作系统?请用一句话描述你对操作系统的理解。
2.你对操作系统和用户程序之间的关系有何看法?阐述你的想法。
3.简要列出操作系统覆盖的范畴及每个范畴的核心内容。
4.你为什么要学习操作系统?与本书列出的理由相同吗?简要阐述你的动机。
5.操作系统要对不同的部件进行管理,请论述这些管理之间的异同点。
6.设备管理要达到的目的是什么?
7.有人说设备管理软件(设备驱动程序)因为经常由第三方提供,因此不应该作为操作系统的一部分。你对
此有何看法?你认为应该如何判断一个软件是否属于操作系统?
8.请列出程序执行过程中操作系统的介入情况。
9.说操作系统是人造学科,根据是什么?
10.人造学科的特点是什么?它对我们学习操作系统有何帮助?
11.OS需要编译器来编译,而编译器的运行需要OS来支持,那到底是谁先出现谁后出现呢?第2章 操作系统历史
引子:不能承受之真
20世纪末21世纪初,美国兴起了励志演讲(motivational speech)大潮,各种人等乐此不疲。在这拨励志大潮
中,出现了多名影响力广泛的励志演讲家。这些演说家所到之处,真是万人空巷,人潮涌动,场面之壮观令
人叹为观止。
其中一位演讲家由于其名望很高接受了电视台采访。
记者:“您在励志演讲领域声名远扬,影响巨大,您的每场演讲都爆满,能否请您阐述一下什么是励志演
说?”
励志演讲家:“你想知道吗?告诉你,我跟你一样,我压根就不知道什么是励志演讲。我只知道励志演讲非
常流行,我只不过是利用这个潮流来赚钱而已。既然大家都喜欢,我就讲,至于我讲的东西是什么意思,我
根本不知道。但是听众很喜欢!”
我想起了一句英语歌谣:sometimes when we touch, the honest is too much!(有时,当我们拥抱时,所感受
的诚实太过分)。也许人们都不喜欢真实,于是成就了很多人在论述操作系统历史(甚至人类历史)时的粉
饰太平。
操作系统的演变就是我们对计算机硬件进行粉饰的过程。
操作系统进化的推动因素
大多数的教材都专门有一章谈论相关领域的历史,操作系统自然也不例外。不过不同的教材谈论历史的目的
却又不同。多数教材是为了铺垫一下本学科的发展背景,让学生了解相关领域里的发展大事,并没有将历史
与现实的发展联系起来。本书谈论的历史则是以史明鉴,不是为了谈论历史而谈论历史,而是为了让学生明
白操作系统为什么是现在这个样子,以及将来会是什么样子。从根本上把握操作系统这一计算机领域核心学
科的脉搏,深刻理解社会变迁给计算机这门人造学科带来的不可抵挡的变化。同时,我们还将揭示计算机发
展史上一些鲜为人知的重要细节,给学生一个窥探全貌的快感。
如前面所述,操作系统的不断发展与改善由两个因素驱动:
●硬件成本不断下降。
●计算机的功能和复杂性不断变化。
就是这些因素决定了操作系统的历史,我们一定要牢牢掌握这两个趋势。一是硬件成本不断降低,就以硬盘
为例,IBM制造的第一张硬磁盘直径达到2米,造价100多万美元,而容量仅仅1MB,而现在一个容量100GB
的硬盘成本只有几十美元。当然,过去的硬盘和今天的硬盘的制造技术完全不同,第1张硬盘的质量坚挺,可以当做咖啡桌使用,而现在的硬盘(指盘片)非常软,根本不能承受重物。二是计算机复杂性不断增加。
这一点对于很多人来说并不感到惊奇。人类做的任何事情,都是越来越复杂。你不整理住的地方很快就乱
了,有没有这种经验?当然,你的生活随着年龄的增长,也会越来越复杂。最初,计算机的组件虽然巨大,但数量少,且功能简单,现在,一台计算机里面包括的元件数量实在是太多了。
硬件成本的下降和计算机复杂性的提高就推动了操作系统的演变。成本降低意味着同样的价格可以买到更先
进的计算机。而复杂性提高自然需要操作系统的能力也得提高。就是这些变化使得操作系统从最初的仅仅几
百或几千行代码的独立库函数,发展到今天多达4000万行代码的操作系统(如Windows XP),而某些Linux
的版本的代码行数更加庞大。
操作系统之所以越来越复杂是因为硬件质量和数量的提升使得操作管理的东西增多,而且人类永不满足的各
种越来越苛刻的要求也使得计算机操作系统的复杂性增加。
另外,还有另外一个附加因素影响着操作系统的发展,这就是操作系统和攻击者之间的博弈。这个世界上总
有些人想利用计算机的缺陷来进行各种损人利己或损人又不利己的活动。操作系统在最初设计时根本就没有
想到会有人从事破坏活动。大概因为最早的计算机工作者认为能够达到使用计算机水平的人都是好人,无需
设计任何安全机制。这样,在后来发现有人试图利用计算机进行不良操作时,就迫不得已修改操作系统,使
其具有安全上的防范功能。每当操作系统改进了安全性,攻击者也会改良他们的攻击手段,这样循环往复,造就操作系统安全水平和攻击者攻击水平不断交替上升。
下面我们就来说一说操作系统是如何因上述驱动因素的变化而变化的。2.1 第一阶段:状态机操作系统(1940年以前)
这是计算机处在萌芽时期出现的操作系统。这种操作系统运行在英国人巴贝斯(Babbes)想象中的自动机
中。所谓状态机操作系统实际上算不上是我们现在通常所定义的操作系统,而是一种简单的状态转换程序:
根据特定输入和现在的特定状态进行状态转换而已。这个时候的计算机也不是现代意义上的计算机,而是所
谓的自动机,其功能非常简单,可以用原始来形容。能做的计算也只限于加减法。这个时代的操作系统没有
什么功能,不支持交互命令输入,也不支持自动程序设计,甚至这个时候还没有存储程序的概念。
驱动这一阶段操作系统的动力是个人英雄主义。因为此时尚无任何计算机工业、计算机研究及计算机用户。
计算机及其操作系统的发展完全是某些人的个人努力。
这个阶段因为计算机刚刚出现,没有多少人能够接触到计算机,自然不存在什么安全问题。
这个阶段没有操作系统。如果非要说有的话,人就是这个时代的操作系统:因为自动机的一切动作均是人在
操控的。2.2 第二阶段:单一操作员单一控制端操作系统(20世纪40年代)
这种单一操作员单一控制终端(Single Operator, Single Console, SOSC)的操作系统是在刚出现计算机时人们
能想到的最直观的控制计算机的方式。这个时候的代表机型为美国宾夕法尼亚大学与其他机构合作制作的
ENIAC计算机。这是第一台电子计算机,但不是第一台计算机。在这之前有个英国人造了一部机械计算
机,通过手柄摇动进行计算。在ENIAC刚造出来的时候,谁都不知道计算机是怎么回事,所以没有操作系
统的整体概念,唯一能想到的就是提供一些标准命令供用户使用,这些标准命令集合就构成了我们的原始操
作系统SOSC。
SOSC操作系统的设计目的是满足基本功能,并提供人机交互。在这种操作系统下,任何时候只能做一件
事,即不支持并发和多道程序运行。操作系统本身只是一组标准库函数而已。操作系统本身并不自我运行,而是等待操作员输入命令再运行。用户想使用什么服务,就直接在命令行键入代表该服务的对应操作系统的
库函数名(文件名)即可。这种操作系统的资源利用率很低:你输入一个命令就执行一个库函数,拨一下动
一下。当操作员在思考时或进行输入输出时,计算机则安静地等待。当然了,从人的角度来看,效率并不
低,你键入什么,计算机就立即执行什么。但从机器的角度考虑,因为时刻都等着人相对较慢的动作,效率
就太低了。
由于这个时代的计算机很稀少,整个世界也只有几台,而人却不是,提高计算机的利用率就变得十分重要。2.3 第三阶段:批处理操作系统(20世纪50年代)
为了提高单一操作员单一控制终端的操作系统SOSC的效率,人们提出了批处理操作系统。在仔细考察了
SOSC后,人们发现,SOSC效率之所以低下,是因为计算机总是在等待人的下一步动作,而人的动作总是很
慢。因此,人们觉得,如果去掉等待人的时间,即让所有的人先想好自己要运行的命令,列成一个清单,打
印在纸带上,然后交给一个工作人员来一批一批地处理,效率不就提高了吗?这样就形成了批处理操作系
统。
批处理操作系统的代表、第二代通用计算机IBM的1401和7094等,就是这样通过减少人机交互的时间而达到
CPU和输入输出利用率的改善。批处理的过程是:用户将自己的程序编在卡片或纸带上,交给计算机管理员
处理。管理员在收到一定数量的用户程序后,将卡片和纸带上的程序和数据通过IBM 1401机器读入,并写
到磁带上。这样每盘磁带通常会含有多个用户的程序。然后,计算机操作员将这盘磁带加载到IBM 7094
上,一个一个地运行用户的程序,运行的结果写在另一个磁盘上。所有用户程序运行结束后,将存有结果的
磁盘取下来,连到IBM 1401机器上打印结果,然后就可以将打印结果交给各个用户了。
很显然,在批处理下,操作系统的功能和复杂性均得到提升。在SOSC环境下,每个用户自己控制程序的开
始和结束。而在批处理下,很多用户的程序一个接一个地存放在磁带上,用户本人并不在场,无法自己控制
程序的开始和结束。而这个任务就交给了批处理操作系统。负责这个任务的操作系统功能就称为批处理监视
器(batch monitor)。而整个批处理操作系统就是由批处理监视器和原来的操作系统库函数组成的,如图2-1
所示。
图 2-1 SOSC和批处理操作系统比较
批处理监视器的功能就是按部就班地执行用户的程序。这个时代的操作系统仍然只能在同一时间执行一个程
序,但此时文件的概念已经出现。之前在SOSC诞生时期没有文件的概念。为什么到批处理时期出现了文件
的概念呢?因为磁带上的多个用户程序必须以某种方式进行隔离,这需要一个抽象的东西来区分。这个抽象
的东西不是别的,就是文件。除了文件管理外,此时的操作系统还能够管理读卡机、磁带、打印机等。此种
操作系统的任务就是加载一个程序、运行、打印结果,然后执行下一个程序。批处理操作系统的两个部分的
关系也很清楚:一部分是控制程序执行,一部分是支持程序执行。
批处理操作系统的重要代表有IBM开发的FORTRAN监视系统FMS,用于IBM 709;IBM开发的基于磁带的
工作监控系统IBSYS,用于IBM 7090和7094;以及密歇根大学开发的UMES(密歇根大学执行系统),用于
IBM 7094。
密歇根大学执行系统(UMES):操作系统的黎明
在当时,世界上最先进的计算机是IBM 7094。作为礼物,IBM分别给密歇根大学(UM)和麻省理工学院
(MIT)各捐赠了一台。密歇根大学坐落在密歇根湖和伊犁湖旁,麻省理工学院紧邻大西洋。IBM的高管喜
欢搞帆船比赛。每次搞帆船比赛都需要使用计算机来安排赛程、计算成绩、打印名次等。因此,IBM在捐赠
机器给UM和MIT时有一个要求:平时归学校使用(MIT的机器还需要与新英格兰周围的学校如达特茅斯学
院等共享),一旦进行帆船比赛就得停下一切计算任务为IBM服务。这当然使得学校很恼火。因为那个时候
很难在程序执行中间停下来,将中间结果保留等以后再执行。只要停下来,就要从头再来。
于是,密歇根大学的R.M.Graham、Bruce Arden和Bernard Galler在1959年开发出了当时著名的MADUMES系
统,即密歇根算法译码器和密歇根大学执行系统。密歇根算法译码器是一种可扩展的程序设计语言,而密歇
根大学执行系统是一个能够保存中间结果的操作系统。有了这个系统,密歇根大学的计算机运行基本上不受
IBM帆船比赛所造成的中断的影响。MIT在知道这个系统后,将其安装到自己的7094机器上。MAD编程语
言随后又进一步移植到Philco、Univac和CDC等机器上,其很多功能后来被加入到FORTRAN语言里。驱动这个阶段操作系统发展的动力是改善效率。因为机器的昂贵,我们不能容忍机器在操作员思考或IO设
备工作期间闲置起来。2.4 第四代:多道批处理操作系统(20世纪60年代)
虽然批处理操作系统无需人机交互过程就能在一定程度上提高计算机的效率,但还是不那么令人满意。因为
CPU和IO设备的运行是串行的,即在程序进行输入输出时,CPU只能等待。CPU需要不断地探询IO是否完
成,因而不能执行别的程序。
由于IO设备的运行速度相对于CPU来说实在太慢,这种让高速设备等待低速设备的状况令人颇感痛心。人
们又想,能否将CPU和IO进行并发呢?即在一个程序输入输出时,让另一个程序继续执行。换句话说,能
否将CPU运行和IO设备的运行重叠起来而改善整个系统的效率呢?答案是肯定的,不过需要付出代价。因
为CPU和IO重叠需要我们将多个程序同时加载到计算机内存里,从而出现了多道批处理操作系统。
在多道批处理操作系统时代,同一时间可以运行多个程序(宏观上),但控制计算机的人还是一个,即用户
将自己的程序交给计算机管理员,由管理员负责将用户的程序加载到计算机里并执行。由于多个程序同时执
行,因此操作系统需要能够在多个程序(工作)之间进行切换,并且能够管理多个IO设备,同时还需要能
够保护一个进程不被另一个进程干扰。
显而易见,操作系统的功能和复杂性都比简单批处理时复杂得多:既要管理工作,又要管理内存,还要管理
CPU调度。
OS360(M):划时代的多道批处理操作系统
典型的多道批处理操作系统是IBM的OS360(M),它由密歇根大学为IBM公司开发(这是该操作系统名称
后面的M所代表的意义)。它运行在IBM的第三代计算机System360、System370、System 4300等上。
OS360在技术上和理念上都是划时代的操作系统,引进了内存的分段管理,但在商业上没有获得广泛使
用。因为它有很多错误。这些错误很难避免,划时代、崭新的东西很难一次做到完美。尽管如此,OS360
还是被公认为一个划时代的操作系统,它同时支持商业和科学应用,而之前的操作系统只能支持科学计算。
IBM随后对OS360(M)进行了改进,使其逐渐演变为一个功能强大、性能可靠的操作系统。这个改进的版
本被命名为OS390。该操作系统提供了资源管理和共享,允许多个IO同时运行,以及CPU和磁盘操作可以
并发。390获得了广泛的商业应用,一直到今天。
驱动这个阶段操作系统发展的动力仍然是改善效率。因为机器的昂贵,我们不能容忍机器(CPU)在IO设
备工作期间闲置起来。同时,我们对计算机的要求也开始多起来。因此,这个阶段还伴随着对用户不断增长
的要求进行满足。2.5 第五代之一:分时操作系统(20世纪70年代)
多道批处理操作系统的出现使计算机的效率(主要是吞吐率)大大提高。不过这时人们又提出了另外一个问
题:将程序制作在卡片上交给计算机管理员来统一运行,将使得用户无法即时获知程序运行的结果。而这是
一个大问题。想想如果你编写了一个程序,却需要让别人去运行,并等上若干天才能知道结果,这个滋味显
然不好受。万一计算机管理员疏忽了,忘记运行你的程序,或者操作错误,导致程序丢失,情况就更加糟
糕。
基于上述原因,人们考虑能否让人回到计算机前面来,每个人自己管自己的程序,但是,大家的程序可以同
时运转。人的因素又引了回来。这看上去与原始的SOSC似乎一样,但有个关键的不同:多个人同时连在计
算机上,每个人看做另外的一个IO终端而已。每个用户拥有一个终端显示器,这些终端显示器经过RS232
穿行线缆与计算机连接。终端显示器只能接收和发送文本命令和信息。计算机在所有连接的终端用户之间进
行分时,即分给每个人有限的时间,只要时间到了,就换一个进程。这种时分切换下的操作系统就是分时操
作系统。
在分时操作系统下,任意时间可以运行多个程序,且用户直接与计算机交互,当场调试程序。这就和单一操
作员单一终端不一样了,从人本转成了物本。在单一操作员单一终端的情况下,一切等着人。以前执行一条
命令就等人,分时系统就是人等机器。这个模型带来一个直接的结果,就是机器不再等你,等你想问题时机
器就切换到别的程序,等你想好了机器我再切换回来,接受你的输入。就这样,计算机就在很多人之间来回
转,你敲个命令就响应,然后切换走。如果时间掌握得好,用户输入完一个命令计算机正好回来,用户就无
需等待。当然,如果一个用户打字速度足够快,可能会觉得计算机慢;如果打字速度非常慢,就有可能觉得
计算机很快。不同的人感觉有可能完全不同。
显然,和前面几代的操作系统比,分时操作系统要复杂得多。相比于多道批处理系统,最主要的变化是资源
的公平管理。在多道批处理下,公平不公平没有人知道。大家交了工作后只管回家等结果。至于自己的程序
排在谁前谁后,抑或占用了多少CPU时间是无关紧要的。现在,大家都坐在计算机显示终端前面,任何的不
公平将立即感觉到。因此,公平的管理用户的CPU时间就变得非常重要。除此之外,池化(pooling)、互
斥、进程通信等机制相继出现,使得分时操作系统的复杂性大为增加。
傲慢的代价:MULTICS操作系统
分时操作系统里面最著名的应该是MULTICS和UNIX。前面讲过,IBM在其捐赠7094给UM和MIT时附加了
一些条件,而这些附加条件使得学校非常恼火,但又不能拒绝(想想别的学校吧,他们连这种恼火的机会都
没有)。为此,UM开发了UMES系统以应对这个问题。MIT则将UMES移植到了自己的7094中。后来大家觉
得只保存中间结果还不是最好的办法,毕竟频繁地保存中间结果等帆船比赛结束后再进行重载仍存在麻烦,于是就想开发一个可支持多用户的分时操作系统,以便一劳永逸地解决这个问题。这个时候MIT想到了密歇
根的R.M.Graham,将其请来。在R.M.Graham的主持下,来自贝尔实验室、DEC(Digital Equipment
Corporation,美国数字仪器公司)和MIT的设计人员同仇敌忾(针对IBM的傲慢),一起努力,开始了
MULTICS分时操作系统的研制。
不过,在MULTICS还没有开发出来时,开发团队内部出现了分歧,贝尔实验室的几个人越来越看不惯DEC
和MIT的人,觉得这伙人的思维方式跟自己不一样,做的东西不专业,觉得和他们一起做研究把自己的水平
降低了,就自立门户,搞出了UNIX,并因此获得图灵奖。而UNIX的出现,使得MULTICS从一面世,就不
能挺立,真是中国历史上“既生瑜,何生亮”在计算机操作系统历史上的完美演绎。不过,MIT最后还是做出
了一个应用于部分商用领域的分时操作系统CTSS(Compatible Time Sharing System)。而DEC公司则做出了
非常成功的VMS操作系统。
分时操作系统通常运行在第三代计算机PDP、VAX和CRAY上,其中PDP、VAX是DEC公司生产的,不过
DEC已经不复存在。CRAY是CRAY公司生产的。
驱动这个阶段操作系统发展的动力是响应时间和对越来越多资源的管理。因为机器的昂贵,我们不能容忍机
器(CPU)在IO设备工作期间闲置。同时,因为人的时间宝贵,我们不能容忍人们坐在机器前漫长等待。
因此发明了分时操作系统来解决这两个问题。因为分时引入的多道程序设计,又造成操作系统的空前复杂,我们需要应对竞争、通信、死锁、保护等一系列的新功能。因此,操作系统在本阶段变得相当复杂。2.6 第五代之二:实时操作系统
随着人类技术的进步,计算机得到了广泛应用。其中的一种应用称为进程控制系统,即使用计算机监控某些
工业进程,并在需要的时候采取行动。所有这些系统都具备一个特点:计算机对这些应用必须在规定时间内
做出响应,否则有可能发生事故或灾难。例如,在工业装配线上,当一个部件从流水线上一个工作站流到下
一个工作站时,这个工作站上的操作必须在规定时间内完成,否则就有可能造成流水线瘫痪,而影响企业的
生产和利润。又例如,在导弹防卫系统中,对来袭导弹的轨迹计算必须在规定时间内完成,否则就可能被来
袭导弹击中而无法做出反应。其他对计算机响应时间有要求的系统包括核反应堆状态监视系统、化学反应堆
监视系统、航空飞行控制系统等。
这种对计算机响应时间有要求的系统通常称为临界系统或应用。而为了满足这些应用对响应时间的要求,人
们开发出了实时操作系统。实时操作系统是指所有任务都在规定时间内完成的操作系统,即必须满足时序可
预测性(timing pre-dictability)。需要注意的是,实时系统并不是指反应很迅速的系统,而是指反应具有时
序可预测性的系统。当然了,在实际中,实时系统通常是反应很迅速的系统。但这是实时系统的一个结果,而不是其定义。
显然,实时操作系统的最重要部分就是进程或工作调度。只有精确、合理和及时的进程调度才能保证响应时
间。当然,对资源的管理也非常重要。没有精密复杂的资源管理,确保进程按时完成就成了一句空话。另
外,基于其使用环境,实时操作系统对可靠性和可用性要求也非常高。如果在这些方面出了问题,时序可预
测性将无法达到。
实时系统通常又分为软实时系统和硬实时系统。软实时系统在规定时间得不到响应所产生的后果是可以承受
的,如流水装配线。即使装配线瘫痪,也只是损失了资金;而硬实时系统在得不到实时响应后则可能产生不
能承受的灾难,如导弹防卫系统。如果反应迟钝,结果就可能是严重损失。
商用实时操作系统的代表有VxWorks和EMC的DART系统。2.7 第六代:现代操作系统(1980年以后)
在20世纪80年代后期,计算机工业获得了井喷式的发展。各种新计算机和新操作系统不断出现和发展,计算
机和操作系统领域均进入了一个百花齐放、百家争鸣的时代。尤其重要的是工作站和个人机的出现,使计算
机大为普及。独享计算机也可以负担得起。这个时候的操作系统代表有:DOS、Windows、UNIX、Linux和
各种主机操作系统,如VM、MVS、VMS等。DOS、Windows、UNIX、Linux通常称为开放式系统操作系
统,分别运行在PC机、VAX和Workstation上。操作系统也重新回到子函数库的状态。
随着硬件越来越便宜,个人机出现在人们的视野中。人们可以拥有自己的计算机,而无需与他人分享。在刚
刚出现个人机的时候,拥有个人机的人感觉很好,而那些需要与别人共享小型机的人则感觉不好。由于个人
机由用户一个人独享,分时操作系统的许多功能就无须存在。因此,个人机操作系统又变回到了标准函数库
系统。这时最著名的当属DOS、Windows 3X、苹果机操作系统(Mac OS)等。
但在独享了一阵个人机后,人们发现,没有分时功能的操作系统使一些事情无法完成。这是因为,虽然只有
一个人在使用机器,但这个人可能想同时做好几件事,例如,同时运行好几个程序,没有分时功能这是不可
能的。于是,人们觉得需要对个人机操作系统进行改善,将各种分时功能又加入了操作系统。
这时候就需要对程序进行保护,因为现在运行多个程序。虽然都是你的东西,但是也不能混淆。于是,Windows NT出现了,Xenix出现了,Ultrix出现了。
这个时候的另外一个特征是网络的出现。网络促进了网络操作系统和分布式操作系统的出现。对于网络操作
系统来说,其任务是将多个计算机虚拟成一个计算机。传统的网络操作系统是在现有操作系统的基础上增加
网络功能,而分布式操作系统则是从一开始就把对多计算机的支持考虑进来,是重新设计的操作系统,所以
比网络操作系统效率高。分布式操作系统除了提供传统操作系统的功能外,还提供多计算机协作的功能。2.8 操作系统的演变过程
计算机操作系统的演变可以分为三条发展线索,分别是主机操作系统、服务器操作系统和个人机操作系统。
图2-2简略地表示了这三条线索上操作系统的演变历史。
图2-2最左面的3列代表主机操作系统的演变,最右面的两列代表个人机操作系统的演变,中间列出了服务器
操作系统的演变。当然,到最后,这三大块的界限也不是很清晰。
图 2-2 操作系统的历史演变
主机操作系统的演变从输入输出控制系统IOCS和IBSYS开始,经历OS360的里程碑式的突破,逐步演变为
VS、MVS和VM三个系列(其中VM系列还吸取了UMES和CTSS的某些特征)。目前IBM是这三个系列的开
发商和运营商,其VM操作系统经历多代后已经变得十分可靠。美国大型金融证券公司都在使用它们。
服务器操作系统的演变从UMES开始,经CTSS演变为IBM的MVS和VM操作系统,经MULTICS演变为UNIX系统。在20世纪80年代初,UNIX一分为二:由AT&T(美国电话电报公司)提供的System系列和由UCB提
供的BSD系列。XENIX为微软公司为PC机而移植的AT&T版的UNIX操作系统。AT&T是UNIX的鼻祖,UCB则在美国国防部的支持下开发了BSD(伯克利软件分配)系列。
IBM和斯坦福大学看到AT&T和UCB的UNIX软件后,也不甘示弱,分别研发了AIX和SUN OS(SUN是
Stanford University Networks(斯坦福大学网络)的缩写)。这样UNIX就形成了4个系列:AT&T的System系
列、IBM的AIX系列、SUN的SUN OS系列以及UCB的BSD系列。
20世纪90年代中期,在美国国防部停止对BSD的支持后,UCB亦停止了BSD系列的研发,而AT&T也在与
BSD焦头烂额的较量中放弃了System系列。Linux则趁AT&T和UCB忙于与对方较量的时候发展起来。卡内
基梅隆大学(Car-negie Mellon University)在看到UCB和斯坦福大学都研发了UNIX后,慌忙开发了个
MACH操作系统。MACH为微内核操作系统,在学术界得到了一定的使用,但由于其运行效率低下而没有获
得商业上的广泛应用。这样UNIX的商业使用版本就剩下AIX、SOLARIS系列(SUN OS的后续版本)和
Linux系列。后来由于惠普公司(HP)加入到服务器行列使得UNIX家族又增加了一个版本:HP-UX。在
UNIX家族中,SUN公司濒临灭亡的命运令SOLARIS的前途堪忧。
个人机操作系统的演变可以说是从DOS开始的。微软公司在1980年以100美元的成本买断了DOS的版权。而
DOS的功能很简单:文件没有文件夹,所有文件都保存在同一个地方,谁都可以删除操作系统。当然那时也
没有那么多人从事破坏活动。在看到苹果公司的Mac OS的图形界面后,微软公司给DOS增加了一个图形界
面,称为Windows。Windows在发展了几个版本后,到Windows 98时,微软公司改变了战略。因为到当时为
止,所有的Windows并不是真正的操作系统,而是覆盖在DOS上的一个用户图形界面,并不支持多道编程。
微软高管比尔·盖茨亲自打电话给DEC的David Cutler,请其过来主持新一代Windows操作系统的研发工作。
David Cutler是DEC公司VMS操作系统的主要设计人员。他从DEC带过来一批人到微软公司工作,设计出了
Windows NT操作系统。这是一个真正的支持多道编程的操作系统。Windows NT继承了VMS的优良结构和
Windows 3X的图形界面,在一推出就获得了市场的认可。Windows NT经过几代演变,成为现在的Windows
Vista。Windows操作系统系列也从单一的支持个人机演变为支持个人机和服务器的“双料”操作系统。
操作系统的分类
操作系统基本上可以分为:主机操作系统,如OS260、OS390、CTSS;服务器操作系统,如UNIX、Windows 2000、Linux;多CPU计算机操作系统,如Novell Netware;个人计算机操作系统Windows 2000、Windows XP、Mac OS;实时操作系统,如VxWorks、DART;嵌入式操作系统,如Palm OS、Windows
CE、Android、Symbian等。
同一台计算机可以运行不同的操作系统,而同一个操作系统也可以运行在不同的计算机上。例如,个人机上
可以运行的操作系统包括DOS、Linux、NeXTSTEP、Windows NT、SCO UNIX等DEC VAX计算机上可以运
行的操作系统有VMS、Ultrix-32、BSD UNIX等。UNIX操作系统可以运行在XENIX 286、APPLE AUX、CRAY-YMP、IBM 360370等计算机上;Windows NTXP可以运行在Intel 386和Itaninum、DEC的Alpha、摩
托罗拉的PowerPC和MIPS计算机的MIPS上。
当然,运行在不同机器上的UNIX版本并不一样,例如运行在IBM 360370上的UNIX是Amdahl UNIX
UTS580和AIXESA,而运行在CRAY-YMP计算机上的UNIX是AT&T System V。2.9 操作系统的未来发展趋势
随着计算机不断普及,操作系统的功能会变得越来越复杂。在这种趋势下,操作系统的发展将面临两个方向
的选择:一是向微内核方向发展,二是向大而全的全方位方向发展。微内核操作系统虽然有不少人在研究,但在工业界获得的承认并不多。这方面的代表是MACH系统。在工业界来说,操作系统是向着多功能、全方
位方向发展。Windows XP操作系统现在有4000万行代码,Windows 7的代码规模更大,某些Linux版本有2亿
行代码,SOLARIS的代码行数也在不断增多。鉴于大而全的操作系统管理起来比较复杂,现代操作系统采
取的都是模块化的方式,即一个小的内核加上模块化的外围管理功能。
例如最新的SOLARIS将操作系统划分为核心内核和可装入模块两个部分。其中核心内核分为:系统调用、调度、内存管理、进程管理、VFS框架、内核锁定、时钟和计时器、中断管理、引导和启动、陷阱管理、CPU管理;可装入模块分为:调度类、文件系统、可加载系统调用、可执行文件格式、流模块、设备和总线
驱动程序等。
最新的Windows将操作系统划分成内核(kernel)、执行体(executive)、视窗和图形驱动和可装入模块。
Windows执行体又划分为:IO管理、文件系统缓存、对象管理、热插拔管理器、能源管理器、安全监视
器、虚拟内存、进程与线程、配置管理器、本地过程调用等。而且,Windows还在用户层设置了数十个功能
模块,可谓功能繁多,结构复杂(见图2-3)。
图 2-3 Windows 2000XP2003系统结构(来源:参考文献[8])
进入21世纪以来,操作系统发展的一个新动态是虚拟化技术和云操作系统的出现。虚拟化技术和云操作系统
虽然听上去有点不易理解,它们不过是传统操作系统和分布式操作系统的延伸和深化。虚拟机扩展的是传统
操作系统,将传统操作系统提供的一个虚拟机变成多个虚拟机,从而同时运行多个传统操作系统;云操作系
统扩展的是分布式操作系统,而这种扩展有两层意思:分布式范围的扩展和分布式从同源到异源的扩展。虚
拟机技术带来的最大好处是闲置计算资源的利用,云操作系统带来的最大好处是分散的计算资源整合和同
化。2.10 讨论:操作系统虚拟化和虚拟化的操作系统
随着虚拟化及云计算等技术的出现和不断演变,人们心目中的各种传统计算技术、模型和理论都在发生改
变。操作系统作为计算机的核心系统软件,其面临的调整或挑战可能更为深刻,也更为细腻。有人断言,虚
拟化将迫使操作系统退出历史舞台,因为操作系统的功能将由虚拟机来替换。但情况的发展似乎并没有为这
种观点提供佐证。
不论从管理者的角度看,还是从魔术师的角度看,虚拟机本身就是一个操作系统,只要虚拟机在运行,操作
系统就在运行,只不过更换了一个名字而已。因此,所谓的操作系统将退出历史舞台一说实属偷换概念。当
然,虚拟机与传统的操作系统有所不同,虚拟机设计的侧重点、功能范畴、某些功能的实现哲学并不完全等
同于传统的操作系统。也许,那些声称操作系统将退出历史舞台的人指的是传统的非虚拟机操作系统。
事实上,传统的操作系统也不会退出历史舞台。不过,其在虚拟化时代发挥作用的方式有可能发生变化。有
迹象表明,传统操作系统扮演的角色在全虚拟化环境下有所收敛并出现专攻趋势。例如,一种已经露出端倪
的倾向是将应用软件和操作系统打包发布,即应用程序与其赖以运行的操作系统的部分功能作为一个软件包
发布出来。用户运行软件时不再需要先安装操作系统,只需要安装一个虚拟机即可。这样不同的软件包可以
打包不同的操作系统,用户无需因为购买了不同的软件而需要安装不同的操作系统。根据应用软件的具体情
况,被打包的操作系统功能部分可能很小,也可能较大,但由于一个应用软件常常不会用到一个传统操作系
统各方面的功能,因此这种打包里面的操作系统功能将不包括整个传统操作系统的功能。
在这种打包发布模式下,用户的运行环境只有虚拟机,而与传统操作系统剥离。应用软件开发商无需针对不
同的操作系统为自己的软件开发多个版本,而只需要支持一种操作系统即可。由于一个应用只为一个操作系
统而写,因此应用软件开发商可以选择一个最能增加应用软件稳定性的操作系统作为平台来打包发布。这样
一个重要的问题就是应用软件开发商如何选择最合适的操作系统。考虑的因素当然包括安全性、稳定性、易
用性、功能性和效率。至于每一个因素所应该占的比重到底是多少,当然是仁者见仁、智者见智,也因软件
开发商的不同而不同。
无论虚拟化或者去虚拟化,无论操作系统与应用软件打包还是不打包,一个不变的因素是扮演魔术师与管理
者角色的这种软件是不可或缺的,不管这个角色是叫做操作系统,还是叫做虚拟机,或者是其他更加令人匪
夷所思的名称。其实,名称叫什么不要紧,关键的问题是学习掌握如何扮演魔术师和管理者。而达到这个目
的途径就是——学习操作系统。
操作系统奇异点
随着人们不断提高对信息安全重视程度,如何构建可靠、可用和安全的操作系统就成为一个十分重要的课
题。而对可靠、可用和安全的追求无疑将令操作系统更复杂,操作系统的规模也将不断增大。从UNIX的
1400行代码到Windows XP的4000万行代码,这完全是一种爆炸式增长。而爆炸式增长的后果就是,操作系
统设计已经变得极为复杂和困难。以致商用操作系统在关键机制的实现上都或多或少地进行了偷工减料,从
而严重影响了操作系统的稳定性。另外,规模的庞大使得没有什么人能够完全理解一个完整的操作系统,而
这种状况同样将限制操作系统的可靠性、可用性和安全性。这迫使我们不得不思考:操作系统能在复杂性和
规模不断增加的情况下保持正确性和可靠性吗?它能在今天的云计算时代取得突破,而达到我们所祈望
的“操作系统奇异点”(OS singularity)吗?
经上写着,不要预测将来。那就让我们拭目以待吧……思考题
1.请列出你曾经用过的所有操作系统。哪个操作系统你觉得最好?为什么?
2.在你用过的操作系统中,你感觉哪个操作系统最好?解释你的答案。
3.计算机从过去单一操作员单一控制终端到现在的个人机,似乎我们转了一个圈。是不是我们人类总是喜欢
反复无常呢?请阐述你对这种否定之否定的观点。
4.虽然我们不赞成对未来进行预测,但你是否对操作系统的未来演变有自己的看法呢?
5.MULTICS的出现在很大程度上是由于IBM的傲慢,你认为人的傲慢在操作系统发展过程中占据什么样的角
色呢?
6.驱动操作系统发展的主要动力有哪些?它们是如何驱动的?
7.很多人都说,没有操作系统的计算机是一堆废铁,无法运转。但在计算机刚诞生的时候,谁也不知道操作
系统这回事儿。那个时候的计算机为什么在没有操作系统的情况下能够运转呢?它们又是如何运转呢?
8.操作系统根据其运行的计算机硬件结构不同而分为主机操作系统、服务器操作系统和个人机操作系统。简
要论述这三种操作系统的关键不同点。
9.MACH所提倡的微内核操作系统因为运行效率低下而没有获得广泛的商业应用,你认为其效率低下的原因
何在?
10.简要论述实时操作系统和分时操作系统的区别。第3章 操作系统基本概念
引子:软件师的尴尬
有一个小幽默也许读者听过,说是三个数学家和三个软件师(即软件工程师或软件专家)在一列火车上相
遇。攀谈中,六个人发现大家都是去参加同一个会议的。然而让软件师们吃惊的是,三个数学家只买了一张
车票,而他们却各买了一张票。
三个软件师于是问数学家:“你们三个人只买一张票,等会儿列车员查票你们怎么办呢?”(这里需要指出的
是,西方的火车站不查票,而是在车上查票。)
三个数学家回答说:“这你们就不懂了吧。你们看好了,学习学习。”
过了不久,果然开始查票。只见三个数学家急急忙忙跑到厕所里面,将门从里面反锁上。查票员过来后敲厕
所的门,问:“查票了,里面有人吗?”里面传来一个声音:“有人,但正在上厕所,无法开门,能否将车票
从门底下递出来检查?”这个时候厕所门下面递出来一张车票。查票员看了没有任何问题,于是就离开了。
三个软件师看完这一幕,十分惊叹。心想,数学家就是比开发软件的人聪明,我们怎么从来没有想到这一招
呢?于是,他们相约回程再同乘一趟车。
过了几天,开完会后,六个人在回程中又聚到了一起。见面后,三个软件师就迫不及待地告诉数学家
们:“我们这次只买了一张票。你们是否也只买了一张票?”
只见数学家们微笑着,不动声色地回答道:“我们这次没有买票。”
软件师们一听,都不敢相信自己的耳朵,接着问道:“那你们这次怎么应付查票呢?”
数学家们丢下一句话:“你们自己想吧。”
软件师们想了半天,实在想不出来有什么办法可以应付查票员。没有办法,只好硬着头皮来问数学家:“我
们想不出来,你们告诉我们吧。”
数学家们仍然微笑着说:“你们的脑袋不够用了吧。看我们再教你们一招。”
过了不久,开始查票了。三个软件师急急忙忙跑到厕所里面,将门从里面反锁上。这时有人敲厕所的门,说:“查票了,里面有人没有?”里面传来一个声音:“有人,但正在上厕所,无法开门,能否将车票从门底
下递出来检查?”这个时候厕所门下面递出来一张车票。
门外的人接了车票,却再也没有递回来……
“差不多”精神
这个幽默对于学软件的人来说,也许不会感到很好笑,可对于学数学的人来说,听后感觉很好笑。开发软件
的人认为数学家的薪水没有他们高,于是编造这么个故事来趁机阿Q一把。
不过静下心仔细想一想,发现数学家的做法还真有点道理。这个道理不是别的,而是因为数学是一门严谨的
学科,一切都以精确为追求(这里是指纯数学,不包括那些不被认为是数学的应用数学)。而软件却没有任
何精确可言,是十足的“差不多”学科。因为软件是一门人造学科,它没有对与错(这里指的是同一功能的不
同实现,而不是说程序不可能出现错误),只有好或坏。我们设计软件的时候,也是觉得差不多就可以了,而没有什么精确的追求。
如果不信,就看看我们是如何分析算法的吧。我们使用所谓的渐进分析,将系数和非决定项都忽略不计,所
谓的“只要数量级对就差不多”。至于软件可靠性、健壮性和成本估算,那就更不用说了,连差不多都不如,而是差很多。
操作系统作为一种软件,自然也是“差不多”就可以了,其中的许多设计都是各种折中的结果,到处体现
着“差不多”精神。读者在学习操作系统时只要留心观察,就会发现很多这些差不多。而要理解这种“差不
多”系统,自然需要抱着一种“差不多”的态度。如果一切吹毛求疵,学习操作系统会非常痛苦,也很难精确
(不好意思,用了一次“精确”)把握操作系统的精髓。
令人欣慰的是,中国人自古就有“差不多”的思维逻辑,因此采纳“差不多”的态度对于中国人是一件很容易的
事情。从这种角度看,学好操作系统是水到渠成的事情。(这里需要强调的是,笔者并不是说计算机学科中
没有任何需要精确的时候,而是说在计算机学科里面体现“差不多”的地方非常多,以致整个学科都带有某种“差不多”的精神)。
前面说过,操作系统是一种软件,它运行在硬件上,又为更高层的应用软件提供服务。因此,对底层硬件的
了解将帮助我们更好地掌握操作系统。下面我们就从计算机硬件开始介绍,探讨一下操作系统的主要概念。3.1 计算机硬件基本知识
从概念上讲,计算机的结构非常简单:首先布置一根总线,然后将各种硬件设备挂在总线上。所有的这些设
备都有一个控制设备,外部设备都由这些控制器与CPU通信。而所有设备之间的通信均需通过总线,如图3-
1所示。图3-1中的粗线条表示总线。
图 3-1 计算机结构概览图
为了提高计算机的效率,人们又设计出了流水线结构,即仿照工业流水装配线,将计算机的功能部件分为多
个梯级,并将计算机的每条指令分拆为同样多个步骤,使每条指令在流水线上流动,到流水线最后一个梯级
时指令执行完毕。流水线上的每个梯级都可以容纳一条指令并同时执行,如图3-2所示。
图 3-2 5个梯级的流水线结构
为了进一步提高计算机的效率,在流水线的基础上,人们又发明了多流水线、超标量计算和超长指令字等多
指令发射机制。这些机制的发明在提升计算机效率(主要是吞吐量)的同时,也极大地增加计算机结构的复
杂度,并对操作系统和编译器提出了更高的要求。
图3-3描述的是一个超标量发射的体系结构。这个结构有两队指令读取和译码单元,以及三个执行单元。通
过一个指令保持缓冲区,就可以实现多路复用(multiplex)和反多路复用(de-multiplex),从而提高系统每
个功能单元的利用率和整个系统的吞吐量。
图 3-3 4个梯级的超标量发射结构
除了指令执行单元外,计算机中的另一个重要部件是指令的存放单元,称为存储架构。存储架构包括了缓
存、主存、磁盘、磁带等。有的情况下还存在多级缓存和外部光盘。图3-4描述的是一个包括寄存器的5级存
储介质构成的存储架构。
从寄存器到磁带,每一级存储媒介的访问延迟和容量均依次增大,而价格却依次降低。寄存器的访问速度最
快,容量最小,但成本最高;磁带的访问速度最慢,容量最大,成本却最低。通过合理搭配,可以形成一个
性价比颇高的存储架构。图 3-4 典型的5级存储结构
磁盘是计算机的主要存储媒介。可以说,没有磁盘,计算机就不能称为计算机,或者说计算机的用处就要大
打折扣。虽然确实存在无磁盘的计算机(即disk-less计算机),但这些计算机都是专用的,并不是给一般用
户用的。磁盘从概念上看非常简单,每张磁盘有多块盘片,盘片两面都可以存储数据。图3-5描述的是典型
的磁盘结构。
图 3-5 典型的磁盘内部结构
中断是计算机里面的一个最为重要的机制,它也是操作系统获得计算机控制权的根本保证。若没有中断,很
难想象操作系统能够完成人们所赋予的任务。中断的基本原理是:设备在完成自己的任务后向CPU发出中
断,CPU判断优先级,然后确定是否响应。如果响应,则执行中断服务程序,并在中断服务程序执行完后继
续执行原来的程序。图3-6简单地描述了中断机制。
中断是一个很复杂的过程,中断处理过程中又可以发生中断,且还可以有所谓的软中断,即软件发出的中
断。透彻理解中断对了解计算机操作系统的运行具有重要意义。因此,对中断机制不甚了解的读者请复习在
计算机组成与体系结构中所学习的中断内容。
图 3-6 磁盘中断的响应流程3.2 抽象
我们已经多次提到过,操作系统提供的是一个抽象。所谓的抽象,就是在根本上存在但现实中不存在的东西
(exist in essence but not in reality)。那么到底怎样理解抽象呢?
抽象来源于具体,但又超越具体。例如,人是具体的动物。但如果将人的具体属性,如肉体和骨架全部剥
离,剩下的就是抽象,即人的灵魂。绘画史上有抽象派,而抽象画所表现的就是现实中不存在的东西,但这
些东西确实又来源于现实,如瓦西里·康定斯基的《海战》(见图3-7)。
图 3-7 康定斯基的《海战》:来源于现实,又高于现实
操作系统提供的抽象自然也来源于现实,就是具体的计算机硬件,如CPU、内存、IO设备等。但又超出这
些现实,给人提供了强于现实的东西,使人和应用软件感觉到更多、更好的硬件存在,而且只存在于操作系
统层面,一般的人才会觉得计算机是可以使用的。
另外,抽象不只是操作系统提供给用户的一个存在,它也存在于操作系统内部。操作系统内部分为不同的功
能块,而不同的功能块之间互相提供的也是抽象。3.3 内核态和用户态
就像世界上的人并不平等一样,并不是所有的程序都是平等的。世界上有的人占有资源多,有的人占有资源
少,有的人来了,别人得让出资源,有的人则专门为别人让出资源。程序也是这样的,有的程序可以访问计
算机的任何资源,有的程序则只能访问少量受限资源。操作系统作为计算机的管理者,自然不能和被管理者
享受一样的待遇。它应该享有更多的方便或权限。为了区分不同的程序的不同权限,人们发明了内核态和用
户态的概念。
那么什么是内核态,什么又是用户态呢?只要想一想现实生活中处于社会核心的人与处于社会边缘的人有什
么区别,就能明白处于核心的人拥有的资源多!因此,内核态就是拥有资源多的状态,或者说访问资源多的
状态,称为特权态。相对来说,用户态就是非特权态,在此种状态下访问的资源将受到限制。如果一个程序
运行在特权态,则该程序就可以访问计算机的任何资源,即它的资源访问不受限制。如果一个程序运行在用
户态,则其资源需求将受到各种限制。
例如,如果要访问操作系统的内核数据结构,如进程表,则需要在特权态下才能办到。如果要访问用户程序
里的数据,则在用户态就可以了。
由于内核态的程序可以访问计算机的所有资源,因此这种程序的可靠性和安全性就显得十分重要。试想如果
一个不可靠的程序在内核态下修改了操作系统的各种内核数据结构,结果会怎样呢?整个系统有可能崩溃。
运行于用户态的程序就比较简单,如果其可靠性和安全性出了问题,其造成的损失只不过是让用户程序崩
溃,而操作系统将继续运行。
很显然,内核态和用户态各有优势:运行在内核态的程序可以访问的资源多,但可靠性、安全性要求高,维
护管理都较复杂;用户态程序程序访问的资源有限,但可靠性、安全性要求低,自然编写维护起来比较简
单。一个程序到底应该运行在内核态还是用户态则取决于其对资源和效率的需求。
一般来说,如果一个程序能够运行于用户态,就应该让它运行在用户态。只在迫不得已的情况下,才让程序
运行于内核态。凡是牵扯到计算机本体根本运行的事情都应该在内核态下执行,只与用户数据和应用相关的
东西则放在用户态执行。另外,对时序要求特别高的操作,也应该在内核态完成。
那么什么样的功能应该在内核态下实现呢?首先,CPU的管理和内存管理都应该在内核态实现。这些功能可
不可以在用户态下实现呢?当然能,但是不太安全。从保障计算机安全的角度来说,CPU和内存的管理必须
在内核态实现。
诊断与测试程序也需要在内核态下实现。因为诊断和测试需要访问计算机的所有资源,否则怎么判断计算机
是否正常呢?就像中医治病,必须把脉触摸病人。你不让中医触摸,他怎么能看病呢(当然,很多人认为中
医是伪科学,根本治不了病,本书对此问题不做讨论)?输入输出管理也一样,因为要访问各种设备和底层
数据结构,所以也必须在内核态实现。
对于文件系统来说,则可以一部分放在用户态,一部分放在内核态。文件系统本身的管理,即文件系统的宏
数据部分的管理必须放在内核态,否则任何人都可能破坏文件系统的结构;用户数据的管理则可以放在用户
态。编译器、网络管理的部分功能、编辑器、用户程序等,自然都可以放在用户态下执行。图3-8描述的是
Windows操作系统的内核态与用户态的界线。
图 3-8 Windows操作系统的内核态与用户态的界线
3.3.1 态势的识别那么计算机是如何知道现在正在运转的程序是内核态程序呢?而正确做出内核态或用户态的判断对系统的正
确运行至关重要。显然做出这种判断需要某种标志。这个标志就是处理器的一个状态位。这个状态位是CPU
状态字里面的一个字位。也就是说,所谓的用户态、内核态实际上是处理器的一种状态,而不是程序的状
态。我们通过设置该状态字,可以将CPU设置为内核态、用户态或者其他的子态(有的CPU有更多种子
态)。一个程序运行时,CPU是什么态,这个程序就运行在什么态。3.3.2 内核态与用户态的实现
前面说过,内核态是特权态,而用户态是普通态。特权态下运行的程序可以访问任何资源,而用户态下的访
问则受到限制。那么这种限制是如何实现的呢?
显然,要限制一个程序对资源的访问,需要对程序执行的每一条指令进行检查才能完成。而这种检查就是地
址翻译。程序发出的每一条指令都要经过这个地址翻译过程。而通过对翻译的控制,就可以限制程序对资源
的访问。关于地址翻译的内容本书将在第12章详细阐述。
为了赋予内核态程序访问所有资源的权限,当系统处于内核态时,内核程序可以绕过内存地址翻译而直接执
行特权指令,如停机指令。这种绕过翻译的做法突破了系统对资源的控制。
本书在介绍完进程和内存后,将再次讨论内核态与用户态的议题。3.4 操作系统结构
操作系统的结构也和操作系统历史类似,经历了好几个阶段。在操作系统刚刚出现时,人们还没有意识到操
作系统的存在,也没有将那些库函数称为操作系统。那个时候,人们想到什么功能,就把那个功能加进来,并没有对所有的功能进行统筹兼顾的计划。自然,那个时候的操作系统就是杂乱的、无结构的。
而随着操作系统的演化,人们对操作系统的认识逐步加深,操作系统慢慢多了一些结构。各种功能归为不同
的功能块,每个功能块相对独立,又经过固定的界面互相联系。任意一个功能块都可以调用另一个功能块的
服务。整个操作系统本身是一个巨大的单一体(monolithical system),运行在内核态下,为用户提供服
务,如图3-9所示。
图 3-9 单一体的操作系统结构
后来人们发现单一体的操作系统结构有很多缺点:功能块之间的关系复杂,修改任意功能块导致其他所有功
能块都需要修改,从而导致操作系统设计开发困难;这种没有层次关系的网状联系容易造成循环调用,形成
死锁,从而导致操作系统可靠性降低。这时候,人们想到了人类社会中的层次关系,何不将人类熟悉的层次
关系搬到操作系统设计里,定义操作系统的层次关系呢?将操作系统的功能分成不同层次,低层次的功能为
紧邻其上一个层次的功能提供服务,而高层次的功能又为更高一个层次的功能提供服务。就像人类团体中的
结构:村长→镇长→县长→市长……如图3-10所示。
图 3-10 层次化的操作系统结构
从图3-9和图3-10可以看出,操作系统的所有功能都在内核态下运行。而这带来了几个问题。首先,操作系
统的所有服务都需要进入内核态才能使用,而从用户态转换为内核态是有时间成本的,这样就造成操作系统
效率低下。在操作系统还比较简单时这个问题并不突出,但随着操作系统功能和复杂性的增加,这种问题就
十分明显了。其次,前面说过,在内核态运行的程序可以访问所有资源,因此其安全性和可靠性要求十分高。在操作系统
规模很小时,将其设计得可靠和安全并不困难。而且,在操作系统历史的早期也没有那么多安全问题,自然
安全上的考虑就不用太多。但随着操作系统越来越大,破坏者的水平越来越高,操作系统的可靠性和安全性
就变得很难达到。只要想一想,1400行代码的操作系统和4000万行代码的操作系统有什么区别就知道了。
因此,人们又想出了一个办法,就是微内核结构,即只将操作系统核心中的核心放在内核态运行,其他功能
都移到用户态运行。这样就同时提高了效率和安全性(见图3-11)。
图 3-11 微内核的操作系统结构
各种操作系统结构各有优缺点,但当前的趋势是第三种模式,即微内核的操作系统结构。至于这个微内核到
底有多“微小”,则是仁者见仁、智者见智。例如,美国卡内基梅隆大学开发的MACH操作系统的内核非常
小,而微软公司的Windows XP的内核就大多了。3.5 进程、内存和文件
进程是操作系统里面的核心概念。它指的是一个运动中的程序。从名字上看,进程表示的就是进展中的程
序。一个程序一旦在计算机里运行起来,它就成为一个进程。操作系统对进程的管理通过进程表来实现。进
程表里存放的是关于进程的一切信息。在任何时候,进程所占有的全部资源,包括分配给该进程的内存、内
核数据结构和软资源形成一个进程核(core)。核快照(core image)代表的是进程在某一特定时刻的状
态。
如果在Linux或UNIX操作系统下编写程序,在出现分段错误(segmentation fault)时,操作系统会自动进行
核倒出(core dump)。“核倒出”把所有计算机的状态保存在一个文件中,通过阅读这个文件的内容可以得
知溢出时的进程状况,从而帮助调试程序。
进程与进程之间可以通信、同步、竞争,并在一定情况下可能形成死锁。这些概念都将在第4章进行详细阐
述。
内存是操作系统里面的另一个核心概念。它是进程的存放场所。如何对内存进行管理,使得数据的读写具有
高效率、高安全、高空间利用率和位置透明的特性是内存管理所要达到的目的。
文件是操作系统提供的外部存储设备的抽象,它是程序和数据的最终存放地点。如何让用户的数据存放变得
容易、方便、可靠和安全是文件系统要解决的问题。3.6 系统调用
前面说过,操作系统是一个系统程序,即为别的程序提供服务的程序。那么操作系统的服务是通过什么方式
提供的呢?答案是系统调用(system call)。系统调用就是操作系统提供的应用程序界面(Application
Programming Interface, API)。用户程序通过调用这些API获得操作系统的服务。例如,如果用户程序需要进
行读磁盘操作,在C程序代码里将使用下面的语句:
result=read(fd, buffer, nbytes);
这个read函数是C语言提供的库函数,而这个库函数本身则是调用的操作系统的read系统调用。注意这里有
两个read,一个是read库函数,由程序语言提供;另一个是read系统调用,由操作系统提供。编译器在看到
上述语句后将read库函数扩展为read系统调用。在真正执行时,操作系统将完成上述文件的读操作。
系统调用按照功能可以划分为六大类:
●进程控制类。
●文件管理类。
●设备管理类。
●内存管理类。
●信息维护类。
●通信类。
系统调用一般不在操作系统原理的课程中论述,而是在操作系统编程或系统编程的课程中论述。这里我们简
单说一下系统调用的过程。系统调用分为三个阶段,分别是:
●参数准备阶段。
●系统调用识别阶段。
●系统调用执行阶段。
在参数准备阶段,需要使用系统服务的程序将系统调用所需要的参数,如上述例子中的fd、buffer、nbytes,压入栈中。然后调用read库函数。read库函数将read系统调用的代码放在一个约定好的寄存器里,通过陷入
(trap,一种中断方式)将控制交给操作系统。由此进入第二个阶段。操作系统获得控制权后,将系统调用
代码从寄存器里取出,与操作系统维护的一张系统调用表进行比较,获得read系统调用的程序体所在的内存
地址。之后跳到该地址,进入到第三阶段,执行系统调用函数。系统调用执行完毕后返回到用户程序(见图
3-12)。图 3-12 read系统调用的过程
系统调用中的参数传递
从图3-12可以看出,read系统调用的参数被压入到栈中,即参数传递是通过栈来进行。但这并不是唯一的参
数传递办法。事实上,这还不是效率最高的传递方法。效率最高的方法是将参数存放在指定的寄存器里面。
由于寄存器的访问速度高于栈,因此这种参数传递将可以提升系统调用执行的效率。例如,在x64体系结构
下,最前面的8个参数由寄存器传递。只有超过8个参数时,后面的参数才通过栈来传递。3.7 壳
3.4节说明了操作系统是如何给用户程序提供服务的。用户程序通过调用操作系统提供的系统调用API来获得
操作系统的各种服务。但使用API需要编程。对于不编程序的用户来说,或对于需要与操作系统进行交互的
用户来说,又怎么使用操作系统的服务呢?
为了向这些不编程的用户提供服务,操作系统提供了一个壳(shell)来与用户交互。每个操作系统都提供某
种壳,以便与用户进行交互。这个壳是覆盖在操作系统服务上面的一个用户界面,既可以是图形界面,也可
以是文本界面。用户在这个界面上输入命令,操作系统则执行这些命令。当然,用户输入的命令不是直接的
操作系统服务,而是所谓的utilities。utilities的功用相当于C语言中的库函数。因为用户不能直接调用系统调
用(至于为什么不能留给读者思考),C语言提供了库函数来解决这个问题。
同理,在壳上用户也不能直接使用操作系统的服务,而是通过utilities来获得操作系统服务。UNIX和Linux的
壳都是文本形式,而Windows的壳是图形界面的。在UNIX和Linux里,要启动一个壳只需要运行shell即可。
在Windows里面,要启动壳需要执行explore.exe。在Linux和UNIX中可以同时启动多个壳,而在Windows下
只能启动一个壳。2006年,微软公司推出了Powershell,从此改变了在Windows下只能启用一个壳的限制。
Powershell是一个文本命令壳,可以运行在Windows XP SP2、Windows Server 2003、Windows Vista和
Windows Server 2008上。Powershell提供了一种类似于UNIX和Linux上utilities的东西,称作cmdlets。用户通
过键入cmdlets里面不同的命令而指挥计算机进行各种操作。
一个壳的具体功能包括如下几项:
●显示提示符,如UNIX下的提示符通常为-和%。
●接受用户命令并执行。
●实现输入输出间接(或间接输入输出)。
●启动后台进程。
●进行工作控制。
●提供伪终端服务。
例如:可以在UNIX shell上执行下述命令:
键入:$date
显示:$September 16,2008
还可以进行输出间接(或间接输出):
键入:$date>file
显示:$
上述命令行里面的“>”符号是间接符号,将输出从显示屏转移到了文件file。如果打开文件file,里面的内容
将是September 16,2008。
还可以同时进行输入和输出间接(或间接输入输出):
$sortfile2
上述命令将file1里面的内容进行排序,然后将排序后的结果存放在文件file2里。
还可以将输出间接发送到打印机:
$cat file1 file2 file3>devlp1
上述命令将file1、file2、file3里面的内容进行连接,然后将结果发送到打印机lp1并打印。
可以启动后台程序:
$make all>log&上述命令启动一个编译后台程序,将编译的结果输出到文件log里。
那么壳是怎么实现的呢?下面是一个最为简单的壳(UNIX shell的伪代码,并不能真正运行):
while(true){
type_prompt;显示命令提示符
read_command(command, parameters)从用户获得命令
if(fork==0){fork一个子进程
execve(command, parameters,0);子进程代码,执行用户命令
}
else{父进程代码段
waitpid(-1,&status,0);等待子进程结束
}
}
这个壳一旦启动,就循环往复直到无穷。它所做的事情很简单:
1)显示命令提示符。
2)等待用户输入命令。
3)使用fork创建一个子进程。
4)使用execve在创建的子进程里执行用户输入的命令。
5)重复步骤1)~4)。
上述程序段里的fork和execve均为UNIX操作系统提供的系统调用。fork的功能是创建一个子进程,并将自己
的一切数据复制到子进程里,也就是说,fork完成的实际上是自我复制。execve的功能是用另外一个程序的
内容覆盖自己,即执行新的程序。
这里值得一提的是,在上述程序代码里,fork命令有两次返回:一次返回值为0,表明是子进程(创建的新
进程),对应if-else复合语句中的if部分;另一次返回值不是0,表明是父进程,对应if-else复合语句中的else
部分,而这个返回值就是子进程的进程ID。也就是说,复合语句if-else的if和else部分在fork完成后都将执
行。这听上去奇怪吗?
如果奇怪,那是因为你看到的是一个程序。我们知道,在一个程序里,if-else语句的if和else两个部分只能有
一个部分执行,而不能两个部分同时执行。我们还知道,一个函数是无法返回两次的。因为只要写了
return,后面的语句就不能再执行了。也就是说,return后面无法再出现return了,即一个函数不能返回两
次。那么fork命令为什么能返回两次呢?
这是因为fork的特殊功能使然。fork的功效是创建一个和自己完全一样的进程。在fork系统调用完成后,我们
面对的是两个进程,而不再是一个进程。这两个进程的程序代码完全一样,就是我们上面给出的代码。在其
中一个进程中,执行的是if部分;在另一个进程中,执行的是else部分。因此,从每一个进程内部来看,复
合语句if-else的语义并没有遭到破坏。
而且,既然在fork后有了两个副本,那么每个副本里都有同样的fork调用语句。从另一个角度讲,有两个程
序调用了fork。这两次调用都需要返回。从内存结构看,这两个程序副本或者进程都有自己的调用栈,并都
有调用返回的位置。对于每一个进程来说,它调用了一次fork,获得了一次返回。因此,从每个进程内部
看,也遵循了函数返回一次的语义。
那么系统中的两个一模一样的进程如何区分呢?这个比较简单,给每个进程一个不同的返回值即可。返回给
父进程的是子进程的进程ID,对应else部分;返回给子进程的是0,对应if部分。
本章论述了操作系统的基本概念。这些概念为下一步的进程、内存、文件和输入输出等章节的学习打下了基
础。在这些概念中,最为关键的是内核态和用户态的定义及其关系。当然,抽象是操作系统的根本,而系统
调用和操作系统结构也非常重要。思考题
1.操作系统提供的用户界面有几种?分别是什么?
2.举出人类社会中采用的几个抽象示例,并与操作系统提供的抽象进行对比。
3.有人认为,内核态程序可以访问任何资源的权限对系统安全造成严重威胁,你怎么看?
4.处理器的状态设置需要在何种态势下完成?为什么?
5.处理器从用户态转为内核态时面临的关键问题是什么?如何解决?
6.下述操作是否可以在用户态下执行?
a)保护中断现场。
b)因系统调用陷入内核。
c)启动外部设备。
d)外设与内存经DMA进行数据交换。
e)缺页中断。
7.论述系统调用和壳之间的关系。
8.操作系统采用层次结构的优点是什么?层次结构有什么缺点?
9.fork是如何实现一次调用两次返回的?它有必要吗?为什么?
10.请调研当前业界通用系统里面缓存、主存、磁盘、磁带的平均容量。11.挑战题:内核态的特权是如何实
现的?第二篇 进程原理篇
恍兮惚兮,其中有像;惚兮恍兮,其中有物
有了基础原理篇的铺垫,我们就可以进入操作系统核心功能部件了。
顾名思义,计算机是用来进行计算的,或者说计算机的基本功能是计算功能。而进行计算的关键部件是计算
机的芯片,即CPU。CPU能够按照一定的顺序进行正确计算是在一个指挥者的控制之下完成的。这个指挥者
就是操作系统。操作系统对CPU进行管理的重要手段就是进程模型,或者说进程是操作系统这个魔术师施法
的道具。
进程是操作系统演化过程中的一个里程碑,由于进程的出现,人类希望的并发从理想变为了现实。从根本上
说,进程出现的动机是人类渴望的并发。进程的出现也让操作系统的复杂性大为增加:由于需要对进程进行
分离存储而导致出现内存管理;由于需要让不同进程有条不紊地往前推进而导致进程调度的出现。显然,理
解进程对理解操作系统十分重要,对其进行管理也就理所当然地成为操作系统的一个关键职责。
本篇包括第4~6章的内容。第4章阐述的内容包括进程出现的逻辑必然性、多道编程的效率、进程的创建和
消亡、进程的状态及其转换、进程与地址空间、进程管理和进程模型的缺陷。第5章讲解的内容包括调度的
目标、先来先服务、时间片轮转、短任务优先、优先级调度、混合调度、实时调度等算法,并对优先级倒挂
和线程的不确定性进行讨论。第6章包括为什么要通信、管道、记名管道、套接字、信号、信号量、共享内
存、消息队列等。
进程从根本上说是操作系统对CPU进行的抽象和装扮
本篇最重要的内容是并发。因为要并发,所以我们发明了进程。第4章 进程
引子:牛顿的困惑
在艾德蒙德·哈雷(Edmond Halley)的耐心劝说和敦促下,牛顿(Issac Newton)(见图4-1)撰写了其传世
名作《自然哲学的数学原理》(Philosophiae Naturalis Principia Mathematica,一部包含牛顿经典力学和万
有引力定律的物理学著作)。在完成此书后,一种困惑始终挥之不去。牛顿写完此书后的总览后对他的朋友
哈雷感叹道:“一切物体的运动规律,天上的、地上的,我已经全部、完美地阐述清楚了。但一个一直困惑
我的问题是:这些规律是从何而来的?或者说这些太空中的天体、地上的物体为什么会遵守这些规律呢?它
们如果不遵守这些规律,难道我们还能把它们怎么样不成?”
如果这些规律是随着时间与整个宇宙一起进化或演变的,则在进化到一半的时候,即在这些规律既是规律,又不是规律,或者说还是“半规律”时,宇宙是如何得以存在的呢?我们知道天体的运行轨道只要偏离一点,其存在就有可能大成问题,如果很多天体都随机运动,则后果将不堪设想。因此,按照“半规律”存在的宇宙
是不可想象的。
剩下的唯一推论就是,这些规律在宇宙出现的一刹那就完美地存在了。或者更为直白地说,这些规律在宇宙
存在之前就已经存在了。而这与《约翰福音》里的In the beginning was the word(太初有道)不谋而合。这
里的word是希腊语原文logos的英文翻译。而logos就是逻辑,就是规律。这句话的意思是在还没有宇宙的时
候,规律就已经存在了。
而由于规律本身不是物质,其存在自然是无中生有了。至于是谁或者什么导致这些规律的存在,那就留给读
者自己去遐思了……
本章讨论的进程也是无中生有。这点与宇宙的运行规律有一些相似。不过与宇宙规律不同的是,我们知道是
谁导致了计算机中进程的出现:人!
当人们面临困境时通常的做法就是:发明新的概念、新的术语或新的机制来解脱困境。
图 4-1 位于剑桥大学三一学院门厅里的牛顿雕像4.1 进程概论
进程管理、内存管理和文件管理是操作系统的三大核心功能。那么什么是进程呢?顾名思义,进程就是进展
中的程序,或者说进程是执行中的程序。就是说,一个程序加载到内存后就变为进程。即:
进程=程序+执行
进程在Multics操作系统出现前叫做工作(job)。工作是IBM用于多道批处理程序设计中的概念。由于历史
的原因,Multics操作系统的研发人员不愿意承用IBM发明的术语,而将工作改为了进程(process)。那么进
程出现的动机是什么呢?
本书在第2章提到,单一操作员单一控制终端、批处理均存在效率低下的问题,即CPU使用率不高。为了提
高CPU利用率,人们想起将多个程序同时加载到计算机里,并发执行。这些同时存在于计算机内存的程序就
称为进程。进程让每个用户感觉到自己独占CPU。因此,进程就是为了在CPU上实现多道编程而出现的概
念,如图4-2所示。
图 4-2 进程让每个用户感觉到自己独占CPU4.2 进程模型
那么进程到底是什么呢?什么是进展中的程序呢?从物理内存的分配来看,每个进程占用一片内存空间,从
这点上说,进程就是内存的某片空间。由于在任意时刻,CPU只能执行一条指令,因此任意时刻在CPU上执
行的进程只有一个,而到底执行哪条指令由物理程序计数器指定。也就是说,在物理层面上,所有进程共用
一个程序计数器。
而从逻辑层面上来看,每个进程可以执行,也可以暂时挂起让别的进程执行,之后又可以接着执行。这样,进程就需要某种办法记住每次挂起时自己所处的执行位置,这样才能在下次接着执行时从正确的地点开始。
因此,从这个角度看,每个进程有着自己的计数器,记录其下一条指令所在的位置。从逻辑上说,程序计数
器可以有很多个。
而从时间上看,每个进程都必须往前推进。在运行一定的时间后,进程都应该完成了一定的工作量,即每次
进程返回,它都处在上次返回点之后。这就像古希腊哲学家赫拉克里特说过的:“一个人不能两次踏入同一
条河流。”进程的这3种概念可以由图4-3表示。
图 4-3 进程模型的3个视角
这里需要注意的是,进程不一定必须终结。事实上,许多系统进程(用来为别的进程提供系统服务的进程)
是不会终结的,除非强制终止或计算机关机。
进程模型的实现
对于操作系统来说,进程是其提供的一种抽象,目的是通过并发来提高系统利用率,同时还能缩短系统响应
时间。这种抽象听上去很不错。但这种抽象是如何实现的呢?或者说,操作系统如何实现进程呢?
首先,任何抽象都需要有一个物理基础。对于进程来说,其物理基础就是程序。程序运行在计算机上,而在
计算机上运行首先需要解决的问题是进程的存储:给进程分配合适的内存,让其有一个安身之处。由于多个
进程可能同时并存,因此进程的存储需要考虑如何让多个进程共享同一个物理内存而不发生冲突。操作系统
解决这个问题的手段是内存管理。
此外,进程运行实际上是指进程在CPU上执行。那么如何将CPU在多个进程之间进行交接或切换,这就是进
程实现需要解决的另一个问题。操作系统解决这个问题的手段就是进程调度:决定在什么时候让什么进程使
用CPU。这个议题将在本书第5章予以讨论。4.3 多道编程的好处
人们发明进程是为了支持多道编程,而进行多道编程的目的则是提高计算机CPU的效率,或者说系统的吞吐
量。例如,如果一个进程有20%的时间使用CPU进行计算,另外80%的时间用来进行IO,则如果使用单道编
程,CPU的利用率只有20%。但如果同时运行两个这样的进程,即进行所谓的2道编程,则CPU利用率将提
高到36%(CPU只在两个进程同时进行IO时才处于闲置状态,因此CPU的利用率为1-0.8×0.8=36%)。这里
忽略了进程切换所需要的系统消耗。
同理,如果同时运行3个这样的进程,则CPU利用率将进一步提高到48.8%。4个进程的CPU利用率将为
59%,5个进程的CPU利用率为67.2%,6个进程的CPU利用率为73.8%,7个进程的CPU利用率为80%。这
样,随着进程数量的增加,也就是随着多道编程的度的增加,CPU利用率将逐步提升,但提升的幅度则逐步
降低,直到某个临界点时为止。这个临界点就是多道编程的极限。超过这个极限,多道编程的好处将逐步消
失,甚至呈下降趋势。对于这个系统来说,多道编程的度达到12以后,CPU利用率已经达到94%,之后CPU
利用率的提升空间就很小了,而因为进程切换所带来的系统消耗则变得非常明显。多道编程的度数与CPU效
率的关系如图4-4所示。
图 4-4 多道编程度数和CPU利用率的关系(IO时间为80%)
这里需要注意的是,图4-4描述的是一种非常简单的模型:所有的进程都进行同样的IO工作量(80%),且
进程切换时间忽略不计。如果情况不是这样,例如不同的进程进行IO的工作量各不相同,且进程切换时间
也需要考虑,则CPU利用率的图线就不是这么简单了。但图4-4所描述的趋势变化仍然成立:随着度的增
加,CPU利用率增加,直到一个临界点。
响应时间改善
除了提高CPU利用率外,多道编程更大的好处是改善系统响应时间,即用户等待时间。毕竟,对于大多数用
户来说,关心的是计算机的响应速度,至于CPU利用率到底有多高,除了系统管理员或者某些有偏执狂的人
外,一般人是不会在意的。
下面我们通过一个多道编程的具体例子来展示多道编程对系统响应时间的改善。假定我们有4个程序,每个
程序花费80%的时间进行IO,20%的时间使用CPU(这种假设非常符合算法中的80-20规律)。每个程序的
启动时间和其需要使用CPU进行计算的分钟数如表4-1所示。
下面我们来看看该计算机里面各个程序的执行情况(所有计算均为大约情况,不是精确情况)。从0点0分开始到0点10分,程序1开始运行。由于系统里只有1个程序,因此属于单道编程状态。单道编程时
CPU的利用率为20%,因此第1个程序在该10分钟里总共使用了CPU达2分钟(其他8分钟都用来进行IO
了)。
从0点10分到0点20分,程序2开始运行,此时程序1尚未结束,系统里将有两个程序,因此属于2道编程。我
们前面计算过,2道编程时CPU利用率为36%,因此在这10分钟时间内,CPU使用了3.6分钟。假定这两个程
序完全平等,那么每个程序使用CPU的时间为1.8分钟。至此,程序1总共运行了2+1.8=3.8分钟CPU时间,程
序2运行了1.8分钟CPU时间。
从0点20分开始到0点30分,程序3开始运行,而程序1和2皆未结束,系统里有3个程序,因此属于3道编程状
态。3道编程时CPU的利用率为48.8%,因此在这10分钟时间内,CPU使用了大约4.8分钟(其他5.2分钟都用
来进行IO了)。同样,假定所有程序完全平等,那么每个程序使用CPU的时间为1.6分钟。至此,程序1总共
运行了3.8+1.6=5.4分钟CPU时间,程序2运行了1.8+1.6=3.4分钟CPU时间,程序3运行了1.6分钟。此时,程序
1离结束还需要2.6分钟的CPU时间,程序2离结束还需0.6分钟的CPU时间,程序3离结束所需要的CPU时间最
短,仅为0.4分钟。
从0点30分开始,程序4开始运行,此时程序1、2、3皆未结束,系统里同时有4个程序,因此属于4道编程。
我们前面计算过,4道编程时CPU利用率为59%。而如果程序3想再运行0.4分钟CPU时间,则整个系统需运行
时间为约2.7分钟(2.7分钟时间内CPU共使用1.6分钟,平均每个程序使用的CPU时间为0.4分钟)。因此,在
0点32.7分时,程序3执行完毕,系统中还剩下程序1、2、4,系统变成3道编程。
此时,程序1总共运行了5.4+0.4=5.8分钟CPU时间,程序2总共运行了3.4+0.4=3.8分钟CPU时间,而程序4则
总共运行了0.4分钟。此时,程序2离结束所需的CPU时间最短,为0.2分钟。那么系统需要运行多长时间才能
使程序2获得0.2分钟的CPU时间呢?答案是1.25分钟。因为3道编程的CPU利用率大约为48%,而1.25分钟内
CPU的使用时间是0.6分钟。3个程序平分,每个程序运行了0.2分钟时间。因此,1.25分钟后,也就是在0点
33.95分,程序2结束运行,系统里只剩下程序1和程序4两个程序。
此时,程序1已经使用了5.8+0.2=6分钟CPU时间,程序4已经使用了0.4+0.2=0.6分钟CPU时间。程序4离结束
所需的CPU时间最短,为0.4分钟。而在约2.2分钟后,即0点41.15分,程序4结束运行,剩下程序1。此时程
序1已经运行了6+0.4=6.4分钟,还需用运行8-6.4=1.6分钟。在单道编程的情况下,该程序则在8分钟后,即0
点49.15分结束运行。读者可自行绘出一张各程序的开始和终止时刻图。
在多道编程环境下,4个程序和整个系统的响应时间为:
而在单道编程环境下,4个程序和整个系统的响应时间为:
由上述两个表格的数据可以看出,多道编程比起单道编程,系统平均响应时间缩短了约21分钟,响应时间改
善程度约47%,这是一个巨大的改善。
当然了,多道编程带来的好处到底有多少与每个程序的性质、多道编程的度数、进程切换消耗等均有关系。
但一般来说,只要度数适当,多道编程总是利大于弊。4.4 进程的产生与消亡
什么事件可以造成进程的产生和消亡呢?当然有很多这样的事件。对于进程产生来说,主要的事件有:
●系统初始化(神创造人)。
●执行进程创立程序(人生子)。
●用户请求创立新进程(试管婴儿)。
在一个系统初始化时,将有许多进程产生。产生的这些进程是系统正常运行必不可少的。这些进程的存在使
得新的进程和用户程序的执行成为可能。例如:在系统初始化后,Windows操作系统将自动产生诸如对话管
理(SMSS)、登录管理(WINLOGON)、安全管理(LSASS)、Windows子系统(CSRSS)、Windows壳
(explore)等系统进程。
在系统初始化后,系统就等待用户输入命令。如果这个用户启动一个程序,如双击一个可执行文件,那么系
统将为这个可执行文件创建一个进程。除此之外,用户也可以在程序里面通过系统调用如fork或者
CreateProcess直接生成新的进程。
造成进程消亡的事件则可以分为四种情况:
●寿终:进程运行完成而退出。
●自杀:进程因错误而自行退出。
●他杀:进程被其他进程所终止。
●处决:进程因异常而被强行终结。
前两种情况均为自愿退出,后两种情况均为非自愿退出。在程序设计时我们追求的是前面两种退出,也算是
我们在虚拟世界里面追求人权(进程权)的努力吧。第3种情况通常是一个父进程发出命令终止一个子进
程。当然,一个用户也可以“杀死”自己的进程,但不能“杀死”别人的进程。但一个超级用户(具有系统管理
员权限)则可以“杀死”任何进程。第4种情况在一个进程进行某种非法操作,如访问出界或者除以0后发生,而这种非法操作将被操作系统捕捉。操作系统捕捉到这种异常后将终结造成异常的进程。4.5 进程的层次结构
我们说过,一个进程在执行过程中可以通过系统调用创建新的进程。这个新创建的进程就称为子进程,而创
建子进程的进程则称为父进程。子进程又可以再创建子进程,这样子子孙孙创建下去就形成了所谓的进程
树。UNIX称这个进程树里面的所有进程为一个进程组,进程组里面的进程分布在不同的层次上,从而形成
一个层次架构。
Windows没有进程组的概念,而是所有进程均地位平等。4.6 进程的状态
我们前面说过,进程可以在CPU上执行,也可以处于挂起状态。显然,一个进程至少有这么两种状态。那么
进程还有别的状态吗?
如果进程在CPU上执行,自然就是执行状态。而如果是挂起状态呢?那就得看是什么原因挂起的。因为操作
系统在进行进程调度时要从挂起的进程中选择一个来执行,所以清楚一个进程挂起的原因对调度的有效推进
十分重要。
那么进程挂起有哪些原因呢?首先是一个进程在运行过程中执行了某种阻塞操作,如读写磁盘。由于阻塞操
作需要等待结果后才能继续执行,因此操作系统将把这个进程挂起,让其他进程运转。另外一种情况是一个
进程执行的时间太长了,为了公平,操作系统将其挂起,让其他进程也有机会执行。
这两种挂起的原因十分不同:第一种挂起是进程自身的原因。这个时候,即使把CPU控制权交给它,它也无
法运行。第二种挂起是操作系统的原因。进程自己并无问题。只要把CPU交给进程,它就可以立即运行。这
样,如果将挂起进程分为这样两类,操作系统在进程调度时就只需要查看第二类进程,而无须浪费时间查看
第一类进程。
因此,将进程分为3种状态:执行、阻塞和就绪,如图4-5所示。
在3种状态之间可以进行各种转换。如果每个状态都可以转换为另外一种状态,则一共有6种转换:
图 4-5 进程的3个典型状态
●执行→就绪
●执行→阻塞
●阻塞→就绪
●就绪→执行
●阻塞→执行
●就绪→阻塞
问题是,上面的转换并不是都可以发生。一个进程在执行时,因为运行时间太长,操作系统可以将其挂起,转换为就绪状态,因此第1种转换是可以的。在进程执行过程中如果执行了某种阻塞操作,则进入阻塞状
态,因此第2种转换也是可以的。一个阻塞的进程在其等待的资源到达后,就可以随时执行,进入就绪状
态,因此第3种转换也是可以的。最后,就绪进程由操作系统调度到CPU上就进入执行状态,因此第4种转换
也是可以的。
但是第5、第6两种转换是不可以的。我们前面讲过,阻塞进程即使被给予CPU,也无法执行,因此操作系统
在调度时并不会在阻塞队列里挑选。因此,阻塞状态无法转换为执行状态。对于处于就绪状态的进程来说,因为它并没有执行,自然无法进入阻塞状态。这就像一个人停滞不前,自然就不会有任何人成为其障碍。因
此,就绪状态无法转换为阻塞状态。
这里需要注意的是,第5、第6两种转换虽然都不存在,但其原因不同。第5种转换不可以是因为我们不让它
发生。如果我们乐意,完全可以让操作系统在阻塞队列里挑选一个进程予以执行,只不过这个进程在执行第
1条指令时就会又发生阻塞(因为其等待的数据尚不可用或者发生异常)。因此,从理论上说,阻塞到执行
是可以的,只不过这种状态转换没有任何实际价值而被操作系统禁止。而第6种状态转换则在理论上是不可
以的。一个进程只能在执行时才可能阻塞,没有执行的进程无法直接转换到阻塞状态。这里阐述的进程的3种典型状态并不是唯一的分类方式。事实上,许多商业操作系统的进程状态不止3个,例
如,Windows的进程有7个状态,Solaris的进程则有6个状态。但不管3个、6个、7个还是几个,其目的都是
便于操作系统管理进程。只要细分对管理有利,我们就细分。否则就维持3个状态。4.7 进程与地址空间
进程空间也称为地址空间。简单来说,地址空间就是进程要用的所有资源。于是所有资源就构成了状态的划
分。由于不可能有两个进程状态完全一样,因此每个进程对应计算机的一种状态,而计算机状态就是所有存
储单元的内容。
地址空间的特点就是被动,自己不能做什么,只提供支持。打个比方。看过演出吗?如话剧、芭蕾、歌剧
等。京剧总看过吧?有个舞台,那些道具和舞台就是地址空间。这些空间本身不能发生任何动作。做动作的
只能是演员。而那些演员就是我们将要讲述的线程。跳上来一个演员就是一个线程,如图4-6所示。
图 4-6 音乐剧《剧院魅影》:舞台布景及设施是地址空间,而舞台上的男女演员是线程
进程与地址空间研究的主要内容是如何让多个进程空间共享一个物理内存。具体来说,就是高效、安全地让
所有进程共享这片物理内存。4.8 进程管理
那么谁管理进程的资源?是操作系统。本书前面说过,Operating的意思就是掌控一切。那么如何掌控呢?操
作系统要掌控一切状态,就必须拥有某些手段或资源。那需要什么手段或资源呢?如果让你监视一群人,要
你掌握他们的一切情况,你第一件要做的事是什么?装监视器?不是!而是要知道这群人到底是哪些人!即
你需要知道并维持关于这群人的各种信息!
4.8.1 进程管理所需要的手段
4.4 节讲到了进程的产生和消亡,但这到底是什么意思呢?产生一个进程对于操作系统来说意味着什么
呢?进程消亡又对操作系统有何影响呢?要回答这个问题只需要看一下一个人的出生对一个社会来说意味着
什么就可以了。在一个人出生后,医院需要在几天内为其建立记录,该记录包括诸如姓名、性别、体重、身
高、父母为何人、在何时何地出生、健康状态等信息,然后该记录用来登记户口、办理身份证等。在完成这
些手续之后,这个人就正式存在了。有了这些记录,政府就可以对这个人进行各种管理了。
与一个社会管理人的过程类似,操作系统要管理进程就要维护关于进程的一些信息。当一个进程产生时,操
作系统也需要为其创建记录。操作系统用于维护进程记录的结构就是进程表或进程控制块(Process Control
Block, PCB)。这个进程表或PCB中存放的就是有关该进程的资料。那么进程表里有什么资料呢?显然,不
同的操作系统维护的进程资料不尽相同。但一般来说,维护的资料信息应当包括寄存器、程序计数器、状态
字、栈指针、优先级、进程ID、信号、创建时间、所耗CPU时间、当前持有的各种句柄等。而采纳的数据结
构主要是线性表、链表和结构(struct),当然也可能使用树和图(网络)结构。例如,Solaris的进程表就使
用了上述4种数据结构。表4-2描述的是一个高度简化的进程表。
这个进程表保持在操作系统所在的内核空间里,如图4-7所示。图 4-7 进程表存放在操作系统所在的内核空间里
如果想更深入地了解进程表的结构,读者可以参阅相关商业操作系统的内核教程。4.8.2 进程的创建过程
前面说过,对于一个计算机系统来说,不断创建和终结进程,创建进程和终结进程各有4种方法。但操作系
统是如何创建一个进程的呢?一般来说,创建进程的步骤如下所示:
1)分配进程控制块。
2)初始化机器寄存器。
3)初始化页表。
4)将程序代码从磁盘读进内存。
5)将处理器状态设置为“用户态”。
6)跳转到程序的起始地址(设置程序计数器)。
这里一个最大的问题是,跳转指令是内核态指令,而在第5步时处理器状态已经被设置为用户态,但在用户
态下是不能执行内核态指令的。这个问题如何解决?当然了,这就需要硬件帮忙了。硬件必须将第5和第6两
步作为一个步骤一起完成。
进程创建在不同的操作系统里方法也不一样。例如,UNIX将进程创建分为两个步骤:第1步是fork,创建一
个与自己完全一样的新进程;第2步是exec,将新的进程的地址空间用另一个程序的内容覆盖,然后跳转到
新程序的起始地址,从而完成新程序的启动。而Windows使用一个系统调用就可以完成进程创建。这个系统
调用就是CreateProcess。在调用该函数时我们把欲执行的程序名称作为参数传过来,创建新的页表,而不需
要复制别的进程。
UNIX和Windows的进程创建过程各有优缺点。UNIX的创建过程要灵活一些,因为我们既可以自我复制,也
可以启动新的程序。而自我复制在很多情况下是很有用的。例如,Web服务器在每收到一个用户请求后,就
创建一个新的一模一样的进程来服务用户请求。而在Windows下,复制自我就要复杂一些了。而且,共享数
据只能通过参数传递来实现。4.8.3 进程管理要处理的问题
进程管理的最大问题是资源分配。那么如何分配资源呢?人类社会最大的问题也是资源分配。谁能解决资源
争端,让地球上每个人高高兴兴地共享资源,谁就是人类的救星。当然,计算机的资源分配问题不像人类那
样困难,因为程序没有自我意识,就算我们对某些程序不公平,它们也无法抱怨。但这不能成为我们偷懒和
堕落的理由。毕竟,我们制造计算机就是想好好地利用它,自然希望能够让所有进程高兴地相处在一起。毕
竟,我们的本性还是追求公平的。
除了公平之外,还有一个问题要考虑:效率,也就是最优。每个进程分配同样的资源肯定不行。以前32个终
端连到一台计算机上,慢得不行,结果没有任何人高兴。不如让部分人先富起来,给他们使用资源的优先
权。
这样,公平与效率就成了进程管理中永恒的主题。到底是公平重要,还是效率重要?天平的不同倾斜将引出
十分不同的进程管理模式。4.9 进程的缺陷
看上去,进程的抽象或模型似乎很好:既提高了系统利用率,又缩短了系统响应时间。它通过支持多道编
程,让我们感觉每个人都拥有自己的CPU和其他资源,似乎皆大欢喜。
难道进程模型就没有任何问题了吗?当然不是。
如果仔细观察,就会发现,进程有个很严重的问题。假定现在有两部很好的电影,都只放映一次,以后再也
不放映了。而且,这两部电影同时放映,当然了,是在不同的两个房间放映。而你很想将这两部电影都看
了,有什么办法吗?假定没有光碟刻录机也没有录像机等。
当然,我们没有办法同时看两部电影。这也是进程的缺点。它只能在一个时间做一件事情。如果想同时做两
件或多件事情,进程就不够用了。
另外,更为重要的是,如果进程在执行的过程中阻塞,例如等待输入,整个进程就将挂起(暂停),而无法
继续执行。这样,即使进程里面有部分工作不依赖于输入数据,也无法推进。
而为了解决上述两个问题,人们就发明了线程。本书将在第三篇对线程进行讨论。思考题
1.发明进程的根本动机是什么?它与程序是什么关系?请予以论述。
2.进程带给我们的最大好处是什么?它有什么缺点吗?
3.进程空间是什么意思?它包括哪些东西?它与进程是什么关系?
4.进程有哪3种状态,分别代表什么意思?
5.在进程的6种状态转换里有两种是不存在的,但它们不存在的理由却不一样。请予以解释。
6.在商用操作系统里,进程的状态通常多于3个,请问,设置多于3个进程状态的可能原因是什么?
7.操作系统管理进程的根本手段是什么?
8.进程管理时的两个重要考虑是公平和效率。除此之外,还有什么因素需要考虑吗?
9.进程的产生与消亡与人的出生与消亡有着某种类比性,你能否予以阐述?10.多道编程是否总能提高CPU的
利用率?为什么?
11.有同学认为在进程状态的6种转换中,从就绪到阻塞在理论上可行(操作系统将就绪进程的状态改变为阻
塞状态),而从阻塞到运行则在理论上不可行,你同意吗?为什么?
12.分析:在内核态下的进程通常共享一个地址空间,这是为什么?第5章 进程调度
引子:恐怖分子的调度
1970年的冬天,加拿大魁北克省渥太华的皇家骑警总部。来自美国联邦调查局、美国中央情报局、加拿大皇
家骑警、加拿大安全情报局的特工和警察领导正在这里举行紧急会议。
一个星期前,一群来自欧洲和中东的政要及大亨在美国乘坐由美国政府安排的列车游览美国壮丽河山的时候
被一群恐怖分子劫持。这列掌握在恐怖分子手中的高级列车已经在美国广袤大地上游荡了一个星期。恐怖分
子身上携带有生物病毒,他们以这些病毒和被他们控制的西方人质作为筹码,要求美国政府在政治和经济上
作出让步,但美国政府一直在口头上虚与委蛇,暗中却布置警察和特工对列车进行了多次反劫持行动,不过
皆没有成功。美国政府的行动激怒了恐怖分子,他们杀死了几名政要,并扬言释放生物病毒。情况万分危
急。
在恐怖分子的要挟下,列车进入了加拿大,在加拿大更加广袤的土地上游荡。恐怖分子继续与美国、加拿大
政府交涉。在加拿大皇家骑警总部召开的会议就是来讨论这列列车的问题。
......
邹恒明 著
ISBN:978-7-111-36692-8
本书纸版由机械工业出版社于2012年出版,电子版由华章分社(北京华章图文信息有限公司)全球范围内制
作与发行。
版权所有,侵权必究
客服热线:+ 86-10-68995265
客服信箱:service@bbbvip.com
官方网址:www.bbbvip.com
新浪微博 @研发书局
腾讯微博 @yanfabook目录
前言
计算机的心智
操作系统的奥秘
操作系统之哲学原理
本书内容安排
基础原理篇
进程原理篇
线程原理篇
内存原理篇
文件原理篇
IO原理篇
多核原理篇
操作系统设计篇
本书特点
第一篇 基础原理篇
第1章 操作系统导论
引子:智者的挑战
1.1 人造与神造
1.2 程序是如何运行的
1.3 什么是操作系统
1.4 魔术与管理
1.5 用户程序与操作系统
1.6 操作系统的范畴
1.7 为什么学习操作系统
思考题
第2章 操作系统历史
引子:不能承受之真
2.1 第一阶段:状态机操作系统(1940年以前)
2.2 第二阶段:单一操作员单一控制端操作系统(20世纪40年代)
2.3 第三阶段:批处理操作系统(20世纪50年代)
2.4 第四代:多道批处理操作系统(20世纪60年代)2.5 第五代之一:分时操作系统(20世纪70年代)
2.6 第五代之二:实时操作系统
2.7 第六代:现代操作系统(1980年以后)
2.8 操作系统的演变过程
2.9 操作系统的未来发展趋势
2.10 讨论:操作系统虚拟化和虚拟化的操作系统
思考题
第3章 操作系统基本概念
引子:软件师的尴尬
3.1 计算机硬件基本知识
3.2 抽象
3.3 内核态和用户态
3.4 操作系统结构
3.5 进程、内存和文件
3.6 系统调用
3.7 壳
思考题
第二篇 进程原理篇
第4章 进程
引子:牛顿的困惑
4.1 进程概论
4.2 进程模型
4.3 多道编程的好处
4.4 进程的产生与消亡
4.5 进程的层次结构
4.6 进程的状态
4.7 进程与地址空间
4.8 进程管理
4.9 进程的缺陷
思考题
第5章 进程调度
引子:恐怖分子的调度
5.1 进程调度的定义5.2 进程调度的目标
5.3 先来先服务调度算法
5.4 时间片轮转算法
5.5 短任务优先算法
5.6 优先级调度算法
5.7 混合调度算法
5.8 其他调度算法
5.9 实时调度算法
5.10 进程调度的过程
5.11 高级议题:调度异常之优先级倒挂
思考题
第6章 进程通信
引子:孤独爆破手的自白
6.1 为什么要通信
6.2 进程对白:管道、记名管道、套接字
6.3 进程电报:信号
6.4 进程旗语:信号量
6.5 进程拥抱:共享内存
6.6 信件发送:消息队列
6.7 其他通信机制
思考题
第三篇 线程原理篇
第7章 线程
引子:亚历山大的分身术
7.1 进程的分身术——线程
7.2 线程管理
7.3 线程模型的实现
7.4 现代操作系统的线程实现模型
7.5 多线程的关系
7.6 讨论:从用户态进入内核态
7.7 讨论:线程的困惑——确定性与非确定性
思考题
第8章 线程同步引子:滑铁卢的同步
8.1 为什么要同步
8.2 线程同步的目的
8.3 锁的进化:金鱼生存
8.4 睡觉与叫醒:生产者与消费者问题
8.5 信号量
8.6 锁、睡觉与叫醒、信号量
8.7 管程
8.8 消息传递
8.9 栅栏
思考题
第9章 死锁应对之哲学原理
引子:迷雾笼罩的加拿大
9.1 为什么会发生死锁
9.2 死锁的描述
9.3 死锁的4个必要条件
9.4 哲学家就餐问题
9.5 死锁的应对
9.6 消除死锁的必要条件
9.7 银行家算法:冒险的代价
9.8 哲学家就餐问题之解
9.9 讨论:死锁的思考——综合治理
9.10 讨论:死锁、活锁与饥饿
思考题
第10章 锁的实现
引子:高登绳结
10.1 以中断启用与禁止来实现锁
10.2 以测试与设置指令来实现锁
10.3 以非繁忙等待、中断启用与禁止来实现锁
10.4 以最少繁忙等待、测试与设置来实现锁
10.5 中断禁止、测试与设置
思考题
第四篇 内存原理篇第11章 基本内存管理
引子:让别人无路可走
11.1 内存管理的环境
11.2 内存管理的目标
11.3 虚拟内存的概念
11.4 操作系统在内存中的位置
11.5 单道编程的内存管理
11.6 多道编程的内存管理
11.7 闲置空间管理
思考题
第12章 页式内存管理
引子:虚拟概念的变现
12.1 基址极限管理模式的问题
12.2 分页内存管理
12.3 分页系统的优缺点
12.4 翻译速度
12.5 缺页中断处理
12.6 锁住页面
12.7 页面尺寸
12.8 内存抖动
思考题
第13章 页面更换算法
引子:黑洞理论的替换
13.1 页面需要更换
13.2 页面更换的目标
13.3 随机更换算法
13.4 先进先出算法
13.5 第二次机会算法
13.6 时钟算法
13.7 最优更换算法
13.8 NRU算法
13.9 LRU算法
13.10 工作集算法13.11 工作集时钟算法
13.12 页面替换策略
思考题
第14章 段式内存管理
引子:否定之否定
14.1 分页系统的缺点
14.2 分段管理系统
14.3 分段的优缺点
14.4 段页式内存管理
14.5 段号是否占用寻址字位
14.6 讨论:否定之否定的嵌套——纯粹分段与逻辑分段、分页与段页
思考题
第五篇 文件原理篇
第15章 磁盘操作
引子:EMC——从不可能到可能
15.1 磁盘组织与管理
15.2 磁盘的结构
15.3 盘面的结构
15.4 磁盘驱动器的访问速度
15.5 操作系统界面
15.6 磁盘调度算法
15.7 讨论:固态盘
15.8 讨论:智能磁盘系统
思考题
第16章 文件系统
引子:掩饰的极致
16.1 为什么需要文件系统
16.2 文件系统
16.3 文件系统的目标
16.4 文件的基本知识
16.5 从用户角度看文件系统
16.6 地址独立的实现机制:文件夹
16.7 文件系统调用16.8 内存映射的文件访问
思考题
第17章 文件系统实现
引子:成功中的失败
17.1 文件系统的布局
17.2 文件的实现
17.3 目录实现:地址独立的实现
17.4 闲置空间管理
思考题
第18章 文件系统性能
引子:从不可能到可能
18.1 文件授权管理
18.2 主动控制:访问控制表
18.3 能力表
18.4 访问控制的实施
18.5 其他文件安全措施
18.6 文件系统性能
18.7 文件系统效率性能
18.8 文件系统设计分析:日志结构的文件系统
18.9 海量数据文件系统
思考题
第六篇 1O原理篇
第19章 输入输出
引子:约翰逊的输出——从没有到爆发
19.1 输入输出
19.2 输入输出的目的
19.3 输入输出硬件
19.4 IO软件
19.5 IO软件分层
思考题
第七篇 多核原理篇
第20章 多核结构与内存
引子:不能承受之热20.1 以量取胜
20.2 多核基本概念
20.3 多核的内存结构
20.4 对称多处理器计算机的启动过程
20.5 多处理器之间的通信
20.6 SMP缓存一致性
20.7 多处理器、超线程和多核的比较
思考题
第21章 多核环境下的进程同步与调度
引子:“多核”帝国的陨落
21.1 多核环境下操作系统的修正
21.2 多核环境下的进程同步与调度
21.3 多核进程同步
21.4 硬件原子操作
21.5 总线锁
21.6 多核环境下的软件同步原语
21.7 旋锁
21.8 其他同步原语
21.9 多核环境下的进程调度
21.10 多核环境下的能耗管理
21.11 讨论:多核系统的性能
思考题
第八篇 操作系统设计篇
第22章 操作系统设计之哲学原理
引子:残缺心智的胜利
22.1 操作系统设计的追求
22.2 操作系统设计的第1条哲学原理:层次架构
22.3 操作系统设计的第2条哲学原理:没有对错
22.4 操作系统设计的第3条哲学原理:懒人哲学
22.5 操作系统设计的第4条哲学原理:让困于人
22.6 操作系统设计的第5条哲学原理:留有余地
22.7 操作系统设计的第6条哲学原理:子虚乌有——海市蜃楼之美
22.8 操作系统设计的第7条哲学原理:时空转换——沧海桑田之变22.9 操作系统设计的第8条哲学原理:策机分离与权利分离
22.10 操作系统设计的第9条哲学原理:简单为美——求于至简,归于永恒
22.11 操作系统设计的第10条哲学原理:适可而止
思考题
结语:失望与希望
参考文献前言
In Pursuit of Absolute Simplicity求于至简,归于永恒
当你在电脑上玩游戏、与朋友聊天或编写一个程序并加载运行的时候,你有没有一种像在观看魔术的感觉?
编写好的程序能够编译运行,计算出结果,并显示或打印出来。你有没有觉得它很神秘?
如果想揭开这层神秘的面纱,你就得学习操作系统。
因为操作系统是掌控计算机运行的系统,在学习它的过程中,读者能够了解程序在计算机上运行的全景,或
者说我们所认为的全景(见图1)。之所以这么说,是因为精确了解程序在计算机上运行的全景是极其困难
的(有人认为这根本就是不可能的)。当然,这里的程序指的是有一定规模的程序,而不是那种只有几行代
码的小程序(trivial program)。从某种程度上说,没有人敢肯定自己清楚计算机在任意时刻所处的状态。例
如,在多流水线计算机上,如果发生中断或异常,我们根本就得不到一个精准的状态。唯一能做的就是推倒
重来。
图 1 风靡世界的游戏《第二生命》计算机的心智
人有心智吗?我想所有人都会回答:有!
人的心智就是人的灵气。这是每一个人的生命之气。就是这个灵气赋予了人丰富的思维、感受和行动能力
(当然,也有人认为这是肉体进化的结果,不过这不是本书要讨论的问题)。
那么计算机有心智吗?这不是一个诡秘或者搞笑的问题。
人们通常认为能够运动的生命都是有灵气的,既然计算机能够完成一些人脑才能够完成的理性任务,它当然
也有心智!而这个心智就是操作系统(见图2)。因为操作系统赋予了计算机活力。虽然读者有可能尚不明
白操作系统是怎么一回事儿,但也许知道若没有操作系统,现代计算机是运转不起来的(这里需排除远古时
代的古老计算机)。操作系统作为计算机赖以运转的控制中心,称其为计算机的心智可谓恰如其分。
图 2 计算机的心智就是操作系统
众所周知,理解或看透一个人的心智是很困难的,所谓画虎画皮难画骨,知人知面难知心。依此类推,既然
操作系统是计算机的心智,恐怕理解起来也是困难重重的了。而这正是许多人在学习和研究操作系统时的共
同感受。操作系统的奥秘
记得小时候常常念过的一首诗是这样的:
从小时候就开始数了。
数到懂事、数到成熟,还没有数清。
天上的星星为什么数不清呢?
像记忆和幻想,永远背负着固执的谜……
对于许多大学计算机及相关专业的同学来说,操作系统就像天上的星星(见图3),隐藏着一个固执的谜,永远学不清楚。不过,操作系统真的学不清楚吗?
不是的。学不清楚是因为没有看到其背后的奥秘。这个奥秘不是所有的人都知道的。即使是研究操作系统的
人也不一定意识到它,更别提计算机初学者了。
图 3 理解操作系统有点类似于数清楚天上的星星
那么这个奥秘是什么呢?
天上的星星数不清是因为我们试图做的事情是数星星。如果我们换个角度,不去数星星,而是寻找星星的设
计师,让他告诉我们星星的数量,不就清楚了吗?
这也正是学习操作系统的奥秘。要理解操作系统,就要找到操作系统的设计师,让他们告诉我们操作系统所
蕴涵的所有秘密。当然,这里的寻找设计师并不是真的找来他们,因为找到所有的设计师是不可能的。这里
的设计师指的是一种抽象,一种所有设计师所共有的人生哲学,因为设计师在设计操作系统时会不自觉地将
自己的思维或人生追求构造在操作系统里,从而赋予操作系统以心智,而操作系统也就在这种心智的指挥下
运行着。操作系统之哲学原理
正如前面所述,让设计师告诉我们操作系统的秘密是理解操作系统的最好办法。他们所用的载体就是其所遵
循的生活哲学,这些生活哲学就是操作系统所遵循的哲学原理。
本书就是试图从这些哲学原理(也就是人类生活哲学)的视角来阐述操作系统,从而揭开操作系统的神秘面
纱。
例如,CPU管理(进程与线程)、内存管理(虚拟存储)、外存管理(文件系统)、IO管理(输入与输
出)等操作系统的核心机制不外乎是对资源的管理,它们都遵循着一切人类资源管理的基本原则,即如何有
效地发掘资源、监控资源、分配资源和回收资源。
除了提供管理的功能外,操作系统还需要保证自己的正常运转,即它必须尽力使自身不发生失效或崩溃,因
为这是提供其他一切功能的基础。这与人类确保自身健康生活作为开发利用资源的前提是一个道理。
如果我们掌握了资源的根本属性,即资源管理必然涉及共享和竞争的管理,理解了操作系统必须首先保障自
己的正常运转,就会理解操作系统的一切行为。前者指引着操作系统功能的设计与进化,后者则推动着操作
系统可靠性的演变。
资源管理也好,保证自身的正确性也好,它们都存在着根本的线索。这条根本线索就是人类在长期的生活实
践中摸索出来的管理社会和保障自身安全的各种办法。这些办法是随着人类哲学思维的变化而改进的。因
此,只要明白了人类的哲学思维,就能明白操作系统所遵循的哲学原理,进而明白整个操作系统的设计与构
造。
除了使操作系统易于理解外,从哲学的层面阐述操作系统的原理还有如下好处:
●操作系统可以变化,但支持其存在的哲学原理是不变的。这样,本书的内容可以在操作系统不断演变的环
境下保持有效,而不会像其他书中的内容,随着时间的推移而过时。
●对于很多人来说,操作系统所采取的机制、策略和手段看上去十分枯燥,如果从哲学原理上给它们赋予人
性的特点,这些机制、策略和手段便不再枯燥。
通过将人生哲学与操作系统结合起来,从操作系统哲学原理的层次阐述操作系统的核心技术,就能够理解和
掌握操作系统的精髓。本书内容安排
为清楚地阐述操作系统的哲学原理,也为了使内容显得紧凑,逻辑上一气呵成,本书只选择了操作系统的核
心内容进行分析,放弃了对操作系统核心以外内容,如安全、多媒体系统、虚拟机技术、光盘技术等的论
述。本书集中精力对操作系统发展的历史背景、进程与线程、内存管理、文件系统、输入与输出、多核环境
下的进程调度和操作系统设计进行了哲学原理层面上的分析与论述,而将安全、多媒体、虚拟机等技术留给
别的专业书籍进行论述。对内容的这种安排有如下好处:
●可使本书重点突出、逻辑清晰、内容连贯,便于学生顺利掌握操作系统的核心与关键。
●操作系统的核心内容经过长久的研究与实践,已经变得较为稳定并且形成了众所公认的标准,讲解起来没
有歧义。
●操作系统的非核心部分由于研究的时间短,工业界参与的程度较低,并无公认的标准,论述起来要么不全
面,要么显得凌乱,使刚刚接触操作系统的读者感到迷惑。
●只要掌握了核心内容的原理,读者便能通过自学掌握操作系统核心以外的知识。
本书覆盖全国硕士研究生入学统一考试计算机学科《研究生考试大纲》中操作系统部分全部内容。
本书分为8篇,分别是基础原理篇、进程原理篇、线程原理篇、内存原理篇、文件原理篇、IO原理篇、多核
原理篇和操作系统设计篇,内容结构如图4所示。
图 4 本书内容结构
基础原理篇
该篇包含第1~3章的内容。第1章的内容包括智者的挑战、人造与神造、程序是如何运行的、什么是操作系
统、魔术与管理、用户程序与操作系统、操作系统范畴和为什么学习操作系统。第2章探讨操作系统演变的
主要过程:从单一控制终端、单一操作员,到批处理、多道批处理、分时操作系统、实时操作系统、现代操
作系统;对商业操作系统演变的过程进行了分析,然后探讨操作系统的分类和未来发展趋势。第3章简要回
顾计算机硬件基本知识,探讨什么是“抽象”,讲解用户态与内核态,阐述操作系统结构、系统调用、操作系
统的壳等知识。
进程原理篇
该篇对操作系统最核心的概念——进程进行讲解,包括第4~6章的内容。第4章阐述进程出现的逻辑必然
性、多道编程的效率、进程的创建和消亡、进程的状态及其转换、进程与地址空间、进程模型的实现和进程
模型的缺陷。第5章讲解进程模型实现的手段:调度,主要内容包括调度的目标,先来先服务、时间片轮
转、短任务优先、优先级调度、混合调度、实时调度等算法,并对优先级倒挂和线程的不确定性进行讨论。
第6章的内容包括为什么要通信、管道、记名管道、套接字、信号、信号量、共享内存、消息队列等。线程原理篇
进程虽然让并发从理想变为现实,但其自身却是串行的:进程只有一个执行序列。若要使进程本身也提供并
发,则需要对线程进行讨论。该篇讨论了进程级的并发机制-线程模型,包括第7~10章的内容。第7章的内
容包括进程分身术——线程、线程管理、线程的用户态和内核态以及混合态实现、现代操作系统的线程实现
模型、多线程之间的关系、线程模型主要考虑的问题等。第8章的内容包括为什么同步、同步的目的、锁原
语的进化、睡觉与叫醒原语、信号量、管程、消息传递和栅栏等。第9章对死锁的产生、发展、防止与避免
进行讲解,并讨论死锁、活锁和饥饿的关系。第10章讲述如何使用中断启用和禁止、测试与设置来实现锁原
语。
内存原理篇
该篇对操作系统的另外一个重要构成部分——内存管理进行阐述,包括第11~14章的内容。第11章讲述内存
管理的环境、内存管理的目标、虚拟内存、操作系统在内存中的位置、单道编程的内存管理、固定加载地
址、多道编程的内存管理、固定分区、非固定分区、交换、地址翻译、闲置空间管理等内容。第12章讲解的
内容包括基址极限的问题、分页管理、页表、页面翻译过程、分页管理系统的优缺点、多级页表、地址翻译
速度、锁住页面、内存抖动和页面尺寸设计。第13章对页面更换算法的来龙去脉、欲达到的目的、各种具体
的页面更换算法进行细致讲解。第14章的内容包括分段管理系统、分段的优缺点、段号与寻址位数,并对否
定之否定在内存管理模式发展过程中的作用进行了讨论。
文件原理篇
该篇对操作系统的第三个核心构件——文件系统进行讲解。包括第15~18章的内容。第15章讲述的内容包括
磁盘结构、磁盘访问速度、磁盘的操作系统界面、磁盘访问过程和磁盘调度。第16章讲述为什么需要文件系
统、什么是文件系统、文件系统的目的、文件的基本知识、文件的存储结构、文件类型、文件访问、文件属
性、文件操作、文件夹、相对与绝对路径、共享与链接、内存映射的文件等内容。第17章的内容包括文件系
统分布、文件的实现、文件夹的实现、共享文件的实现、磁盘空间的管理等。第18章的内容包括文件安全性
能(文件访问控制、访问控制表、能力表)、文件可靠性能(持久性、一致性、日志、交易、随影、一致性
检查)和文件系统的效率性能(提前读取、减少磁臂移动距离、日志结构的文件系统LFS)。
IO原理篇
该篇对计算机与外界进行沟通的机制——输入与输出进行讲解。该篇仅有一章(第19章),讨论的内容包括
输入输出的重要性和目的、输入输出硬件的哲学原理、物理IO模式(专有通道IO、内存映射的IO、复合
IO、DMA)、输入输出软件的哲学原理、软件IO模式(可编程IO、中断驱动的IO、DMA)、IO软件分
层和设备驱动程序等。
多核原理篇
该篇对新出现的多核技术进行讲解,重点讨论多核环境给操作系统带来的影响。该篇分为多核结构和多核环
境下的进程同步与调度两章。第20章讲解的内容包括多核处理器结构(超线程结构、多核结构、多核超线程
结构)、多核内存结构(UMA、NUMA、COMA、NORMA)、对称多核处理器计算机的启动过程、多处
理器之间的通信、SMP缓存一致性等。第21章的内容包括多核进程同步、多核环境下的软件同步原语、旋锁
及其实现、队列旋锁、多核环境下的进程调度、多核环境下的能耗管理和多核系统性能。
操作系统设计篇
该篇从高屋建瓴的角度对操作系统设计的十条哲学原理进行阐述。显然,操作系统的设计原则有很多,本篇
选取的只是诸多原则里面非常重要的十条。第22章将从操作系统和人类社会两个层面对这十条原理进行论述
与比较,以使读者更加清楚地明白操作系统就是人类社会在计算机里面的反映。读者可自行发现操作系统的
其他设计原则。本书特点
本书从哲学的视角对操作系统阐述了独到的见解。从人类自然的行为规范推演到操作系统的设计,以一条逻
辑主线演绎了整个操作系统的各种原理。本书的特点是抽象提升(即从哲学原理上阐述操作系统的各种原理
与设计)、联系生活(即通过人所熟知的生活实例来分析操作系统)、模块整合(即将操作系统的各个模块
通过举例连结起来)、逻辑贯通(即将操作系统的各种机制以一根逻辑主线的发展依次讲解)和系统关联
(即将涉及的其他学科知识点如体系结构和编译器等嵌入进来)。本书内容上更加新颖、系统上更加完整、逻辑上更加连贯、解说上更加易懂和层次上更加丰富的特点。
读者在阅读学习完本书后,将达到如下目标:
★了解操作系统在计算机软硬件整个体系中的中心主导作用。
★掌握操作系统的基本概念、原理、技术和实现机制。
★理解操作系统原理背后的人文背景与历史动机。
★运用操作系统知识来分析和解决问题。
★掌握操作系统设计的原理,为以后设计操作系统打下基础。
这里需要提醒的是,本书阐述的是操作系统的原理,它不依赖于任何具体的实现,而是凌驾于所有具体商业
操作系统的进程实现之上,即本书所阐述的思想和原理对所有操作系统都适用。但具体商业操作系统在应用
这些原理时可以有很灵活的方式。事实上,具体的商业操作系统在应用这些原理时确实采取了不同的方式,有的更为精密,也有的更加精简。另外,由于我们注重的是原理,对个体机制实现时采取的数据结构通常不
做详细的论述,而是点到为止。这是因为数据结构必须以真正的操作系统为蓝本进行讲解,而真正的商业操
作系统使用的数据结构通常非常复杂,对此进行繁琐的讲解将把学生弄得晕头转向,而不利于对操作系统核
心原理的把握。
当然了,如果要达到能够设计开发真正商业操作系统的境界,读者还需要进行“操作系统工程”或“操作系统
实现”等知识的学习。而这种工程或实现的课程通常以具体的操作系统为对象进行讲述。这些具体操作系统
可以是Windows、UNIX、Linux,当然也可以是其他一些非主流商业操作系统(如Android、Symbian等)。
如果能够将本书阐述的原理与操作系统工程或实现相结合,将取得极好的效果。
此外,本书使用的伪代码采用类似CC++的结构,每种原理的表示均以展示操作系统的思路为最高目标,并
不对表示的细节进行优化,以使得逻辑清晰,方便绝大多数读者理解。
现在就让我们一起来揭示秘密,数清操作系统里的星星吧。第一篇 基础原理篇
大伪似真,大道无形
对于任何一门课来说,首要探讨的问题就是这门课的主题到底是什么。对于刚接触操作系统的入门者来说,自然想到的问题当然也会是操作系统到底是什么东西。回答这个问题是本篇的职责。此外,操作系统作为计
算机的核心控制系统,它在计算机运行过程中扮演什么角色?它的来历是什么?它有一些什么基本概念?我
们应该如何看待操作系统?它是如何参与到程序的执行过程中的?这些也是学习操作系统需要回答的基本问
题。
本篇就是针对上述问题而写成。它对这些问题进行解答和讨论,并为我们接下来介绍操作系统的核心功能部
件打下基础和铺垫。本篇包含第1~3章的内容。第1章的内容包括智者的挑战、人造与神造、程序是如何运
行的、什么是操作系统、魔术与管理、用户程序与操作系统、操作系统范畴和为什么学习操作系统。第2章
探讨操作系统演变的主要过程:从单一操作员单一控制终端,到批处理、多道批处理、分时操作系统、实时
操作系统、现代操作系统;对商业操作系统演变的过程进行了分析,然后探讨操作系统的分类和未来发展趋
势。第3章简要回顾计算机硬件基本知识,探讨什么是“抽象”,讲解用户态与内核态,阐述操作系统结构、系统调用、操作系统的壳等知识。
本篇最为重要的核心思想是操作系统在计算机运行过程中扮演的角色:魔术师和管理者。魔术师将丑陋变得
美好,将没有变为有,将少变为多;而管理者则对所有计算机资源进行管理以达到公平和效率的“双料”境
界。对操作系统这两个角色的理解将非常有助于对进程、线程、虚拟内存、文件系统和输入输出系统的掌
握。
化丑为美:魔术师是操作系统扮演的一个根本角色第1章 操作系统导论
引子:智者的挑战
西方有一个著名的故事,名曰:智者的挑战。相传很久以前,有个村子里住着一位智者。同村有个年轻人学
到一些知识后就想来挑战这位智者。于是,年轻人想到了一个方法。他来到智者面前,将双手放在背后,问
这个智者:
“我刚刚从树上抓了只鸟,现在我手中。但你能告诉我,这只鸟是活的还是死的呢?”
这是一个诡诈的问题。因为,如果回答“是活的”,则这个年轻人只需要在背后将鸟掐死,然后给智者看这只
死鸟;如果回答“是死的”,则这个年轻人只需要将鸟放飞即可。这样,无论智者如何回答,年轻人都可以让
智者答错,然后可以大大地嘲笑一番智者的水平。
作为智者,当然一眼就看出了年轻人的诡计。但是又不能不回答这个问题。因为不回答问题等于承认答不上
来,当然也就是不是什么智者了。但如何回答呢?
智者的回答简洁、精妙,甚至妙不可言:As you will。
will这个词在英语中的意思是意愿或意志。因此这个答案的意思是:这只鸟的死活与年轻人的意志保持一
致:年轻人的意志是让这只鸟活,则这只鸟就是活的;年轻人的意志是让这只鸟死,则这只鸟就是死的。
如果到此止步,则这个答案仍存在着巨大的漏洞:年轻人可以将鸟掐死,但坚持说自己的意志是让鸟活着,即自己不小心将鸟掐死了,而自己的意志却是想让鸟活着。若是这样的话,智者的回答就错了。
妙不可言的是,will在英语中还有一层意思:将要,即将要发生的事或将要采取的行动。就是说,这只鸟的
死活与年轻人将要采取的行动保持一致:年轻人将要放飞这只鸟,则这只鸟就是活的;年轻人将要掐死这只
鸟,则这只鸟就是死的。
因此,智者的回答将人的意志与行为全部包括了进来。这样,即使年轻人声称他的意愿和行为并不一致,智
者的回答也正确无误。
好,我们知道了智者的回答。但这与操作系统课程有什么关系吗?
有!很多人都觉得操作系统枯燥、乏味,甚至令人厌烦。更有人说懂不懂操作系统没有关系。不是很多人在
学习操作系统之前就已经写过程序了吗?有的人甚至已经写过很大很复杂的程序了。可见,不懂操作系统并
不妨碍我们学习使用计算机。
如果读者这样想,我劝你再想一想。你虽然写过程序,可你知道程序到底是如何在计算机上运行的吗?如果
不知道,你怎么敢肯定你的程序总会运行正确呢?你怎么敢说你写的程序最大限度地利用了系统的能力呢?
一个人觉得操作系统没用,那是因为他不知道怎么用,或者他没有用操作系统的意愿。说明白一点,如果你
认为操作系统没有用,那是因为你的编程和程序开发处在一个低级的水平上。如果你掌握了操作系统,你的
编程水平将显著提高。
换句话说,操作系统有没有用,我的回答是As you will。你如果有意愿或者有行动使用操作系统,操作系
统就是有用的;如果你没有意愿或行动,则操作系统就是没有用的。当然了,我希望读者在看完这本书后能
够领悟到操作系统的巨大用途。万一在读完本书后,读者还感觉困惑或者认为操作系统没用,我唯一能说的
也是As you will了。当然,我希望这种情况发生的概率不大。1.1 人造与神造
要想学好操作系统,具有恰当的思维模式是十分必要的。这个思维模式就是本书所强调的“哲学”:一种思维
方式或一种生活方式。我们以一个问题来说明这一点。这个问题是:
“什么是计算机的根本特征?”
对于这个问题,相信很多人会说计算机就是台计算机器,或者用来进行大规模计算的机器,或者用于数据处
理的机器,或者具备某些其他具体功能的机器。这些回答当然没有错,问题是这些答案并不能帮助我们更好
地学习和理解计算机。就像我们问“张三这个人的根本特征是什么”,而回答却是“张三有175cm高”一样。这
种答案虽然是正确的,但意义不大,因为我们无法从答案中推导出一系列有用的结论。
那这个问题该如何回答呢?这就要看我们对事物的观察程度了。如果我们仔细看看身边的事物,就会发现所
有的东西可以划分为两类:一类是本来就存在于自然中,人类所做的只不过是发现;另一类是本来并不存
在,人类所做的是发明。前者称为神造事物或者自然存在的事物,后者当然就是人造事物。从这个思维模式
上看,计算机毫无疑问就是人造事物。这正是我们所需要的答案,即计算机的根本特征是“人造”。
引申一下可知,计算机学科就是一个人造学科。那么知道计算机学科是人造学科对我们学习计算机有什么帮
助呢?有,太多了。下面我们来看看人造和神造有什么区别。
人造学科的四个特点:
●不精确、具有相对性。
●从对人类活动的观察导出。
●依赖于人的主观判断力。
●通常符合人的直觉。
第一个特点就是所谓的“没有对错”。在人造学科里,没有什么绝对的对或错,而只有所谓
的“好”或“坏”,“有意义”或“没意义”。例如,如果本书在讨论计算机时对某个方面的论述与你见到的计算机
不一样,这并不能说明本书错了。就算世界上不存在本书所论述的计算机,也不能说明本书错了。我们只需
要按照本书的论述再造一台计算机即可。但是,本书论述的计算机与你知道的计算机之间可以进行好和坏的
比较。
第二个特点说的是人造学科是从哪里得到灵感的,那就是“对人类活动的观察”。这样,读者只要对人类生活
仔细观察,就可以很容易地理解计算机里面的许多原理。例如,在操作系统里面广泛使用的栈和队列就是对
从生活中观察到的现象进行抽象所获得,如图1-1所示。
图 1-1 从观察人类活动而获得的栈和队列结构
第三个特点说的是在人造学科里,人的主观能动性起着关键作用。不同的人观察同样的现象,得出的结论或
抽象出的东西可能不一样,甚至完全相反。这样,多数人所认同的抽象就将成为人造学科里的标准,即存在少数服从多数的原则。
第四个特点说的是人造学科里面的许多原理与人的直觉直接呼应,即如果我们按照人的直觉去理解这些原
理,就会十分直截了当。例如,操作系统里面的同步机制与人类男女谈恋爱时所用的约会机制十分相似。对
于一个谈过恋爱或与别人约会过的人来说,如果将自己谈恋爱的直觉用在操作系统进程的学习上,就会发现
进程同步是个十分容易理解的概念。
相对人造学科,自然存在或神造学科刚好具有相反的四个属性:
●精确、绝对。
●从对自然存在的观察导出。
●不依赖于人的主观判断力。
●通常违反人的直觉。
第一个特点说的是神造的事物具有精确、绝对的属性。对于这种学科,存在正确与错误之分,我们提出的观
点要么正确,要么错误,不存在中间状态。例如,纯数学领域的各种运算,如22的结果应该是4。如果运算
的结果不是4,则属于运算错误。
第二个特点说的是人类对这些事物的理解是从对自然存在的观察中获得。例如,牛顿通过观察苹果落地的自
然现象和严密的推理,得出了万有引力定律。
第三个特点说的是这些观察的结果是不依赖于人的主观能动性的。如果一个人的观察结果是正确的话,那么
他的观察将和所有观察正确的人的结果一样,而绝不会是两样。从另外一个角度说,一个人的观察抽象结果
是可以被他人验证的。例如,30 000 000 000+20 000 000 000对于任何人来说,如果计算正确,则结果必然
是50 000 000 000。
第四个特点说的是如果我们按照人的直觉来学习,就会面临重重困难。因为人的思维与神不一样。自然,按
照人的思维模式将很难理解神所创造的这一切。这就是为什么在这些学科耕耘的人都必须依赖灵感的出现,以及严密、一丝不苟的数学与逻辑推理(见图1-2)。
明白了计算机是人造事物,操作系统是一个人造系统,我们就可以按照人造事物的特点来学习,从而易如反
掌地掌握操作系统的原理。
图 1-2 从观察自然存在和严密的数学推理而获得的质能方程1.2 程序是如何运行的
计算机程序是如何运行的呢?对于多数人来说,或多或少地知道任何程序必须首先得有人写出来,即编程,然后放到计算机运行。这种解释当然是过于简单了。计算机程序的运行实际上是一件十分复杂的事情,牵扯
到方方面面。
首先,当然得进行编程,而编程需要计算机程序设计语言作为基础。对于绝大多数编写程序的人来说,使用
的编程语言称为高级程序设计语言,如C、C++、Java等。但由于计算机并不认识高级语言编写的程序,编
好的程序需要进行编译变成计算机能够识别的机器语言程序,而这需要编译器和汇编器的帮助。其次,机器
语言程序需要加载到内存,形成一个运动中的程序,即进程,而这需要操作系统的帮助。进程需要在计算机
芯片CPU上执行才算是真正在执行,而将进程调度到CPU上运行也由操作系统完成。最后,在CPU上执行的
机器语言指令需要变成能够在一个个时钟脉冲里执行的基本操作,这需要指令集结构和计算机硬件的支持,而整个程序的执行过程还需要操作系统提供的服务和程序语言提供的执行环境(runtime environment)。这
样,一个从程序到微指令执行的过程就完成了。图1-3所示的就是这个过程。
当然了,图1-3描述的从程序到结果的演变过程还是过于简单。我们只是从一个线性角度来看程序的演变过
程,而没有考虑各种因素之间的穿插和交互过程。不过,对于刚入门的计算机专业学生来说,这种描述能够
帮助理解整个程序是如何在计算机上执行的问题。
图 1-3 由程序到结果的演变
从这个描述中可以看出:程序的运行至少需要如下四个因素:
●程序设计语言。
●编译系统。
●操作系统。
●指令集结构(计算机硬件系统)。这四个因素都将是大学学习的专业课程。需要注意的是,操作系统在程序的执行过程中具有关键的作用,本
书要做的就是阐述这个关键作用是如何发挥的。
需要注意的是,图1-3给出的程序执行过程是从高级语言编写的程序开始的。而实际上并非总是这样。事实
上,程序可以直接在机器语言或汇编语言上编写。用这种称为“低级”的语言编写出来的机器语言程序无需经
过编译器的翻译就可以在计算机指令集上执行。如果是在汇编语言上编写的汇编程序,则只需要经过汇编器
的翻译即可加载执行。1.3 什么是操作系统
操作系统这个术语听上去稀松平常,并不给人任何兴奋的感觉,甚至有点俗气。原因在于中文的“操作”这个
词:提到操作员,通常让人想起操作车床、磨床和起重机的穿着油腻工作服的工人,这自然让人兴奋不起
来。将英文的operating翻译为中文的“操作”,是因为翻译的人没有理解英文Operating Systems(OS,操作系
统)这个名字所蕴涵的精髓。
那么英文的Operating Systems意味着什么呢?
各位见过手术过程吗?在手术室里,主刀大夫称为Operating Surgeon。在整个手术过程中,主刀大夫具有至
高无上的权威:他说要打麻药,麻醉师便要赶紧打麻药;他说需要手术钳,助理大夫就赶忙递给他手术钳;
他说需要止血,护士就要忙不迭地拿止血药棉来止血。整个手术最关键的部分,切开皮肤、拿掉器官、安装
移植器官等均由主刀大夫完成。当然,主刀大夫有时候也会将某些任务,如缝合创口,交给助理大夫或护士
来做,但整个手术的过程皆由其主控。一句话,Operating Surgeon就是掌控整个手术过程、具有精湛技术和
敏锐判断力的医师。
引申至非医学领域,Operating Person意思是操刀手,就是掌控事情的人。再将Person这个词换成System,则
Operating Systems指的就是掌控局势的一种系统。也就是说计算机里面的一切事情均由Operating Systems来
掌控。那么,我们现在面临两个问题:第一个问题是,操作系统到底是什么东西?第二个问题是,操作系统
到底操控什么事情?
我们先回答第一个问题。既然操作系统是掌控计算机局势的一个系统,自然很重要。但这个说法并不能帮助
读者理解操作系统,也无法形成有形的概念。如果我们换个说法:操作系统是介于计算机和应用软件之间的
一个软件系统,则概念就具体多了。从这个定义出发,我们知道操作系统的上面和下面都有别的对象存在:
下面是硬件平台,上面是应用软件,如图1-4所示。
图 1-4 操作系统上下界面
现在回答第二个问题。我们知道操作系统代表的是掌控事情的系统,掌控什么事情呢?当然是计算机上或计
算机里发生的一切事情。最原始的计算机并没有操作系统,而是直接由人来掌控事情,即所谓的单一控制终
端、单一操作员模式。但是随着计算机复杂性的增长,人已经不能胜任直接掌控计算机了。于是我们编写出
操作系统这个“软件”来掌控计算机,将人类从日益复杂的掌控任务中解脱出来。这个掌控有着多层深远的意
义。
首先,由于计算机的功能和复杂性不断发生变化(趋向更加复杂),操作系统所掌控的事情也就越来越多,越来越复杂。同时,操作系统本身能够使用的资源也不断增多(如内存容量)。这是早期驱动操作系统不断
改善的根本原因。
其次,既然操作系统是专门掌控计算机的,那么计算机上发生的所有事情自然需要操作系统的知晓和许可,未经操作系统同意的任何事情均视为非法的,也就是病毒和入侵攻击所试图运作的事情。作为操作系统的设
计人员,我们当然要确保计算机不发生任何我们不知情或不同意的事情。但是人的能力是有限的,人的思维
也是有缺陷的,我们设计出的系统自然不会十全十美,也会有缺陷,这就给了攻击者可乘之机。操作系统设
计人员和攻击者之间的博弈是当前驱动操作系统改善的一个重要动力。
再次,掌控事情的水平有高低之分,有效率不同之分。就像手术大夫之间也有水平高低之分。为了更好地掌
控事情,同时也为了更好地满足人类永不知足的各种越来越苛刻的要求,操作系统自然需要不断改善。这种
改善在过去、现在和将来都会继续下去的。最后,我们可以给操作系统下定义了:
●操作系统是一个软件系统;
●操作系统使计算机变得好用(将人类从繁琐、复杂的对机器掌控的任务中解脱);
●操作系统使计算机运作变得有序(操作系统掌控计算机上所有的事情)。总结起来就是:操作系统是掌控
计算机上所有事情的软件系统。
从这个定义可以引申出操作系统的功能:
●替用户及其应用管理计算机上的软硬件资源。
●保证计算机资源的公平竞争和使用。
●防止对计算机资源的非法侵占和使用。
●保证操作系统自身正常运转。1.4 魔术与管理
提升上面所列的操作系统功能,可以得出操作系统所扮演的两个根本角色:管理者和魔术家。只要记住了这
两个角色,就差不多明白了什么是操作系统。
1.4.1 魔术家角色
魔术家的目标是把差的东西变好,把少的东西变多,把复杂变简单。同样,操作系统将计算机以一个更加容
易、更加方便、更加强大的方式呈现给用户。例如,如果在裸机上直接编程是很困难的,因为各种数据转移
均需要用户自己来控制,对不同设备要用不同命令来驱动,而这对一般人很难胜任。操作系统将这些工作从
用户手中接过来,从而让用户感觉编程是一件容易的事(相对来说,编程对于有些人来说永远很难),如图
1-5所示。
操作系统通过进程抽象让每一个用户感觉有一台自己独享的CPU;通过虚拟内存抽象,让用户感觉物理内存
空间具有无限扩张性,这就是把少变多。当然,操作系统的把少变多不是无中生有,变多也不是无限多,只
是针对磁盘容量的大小。1.4.2 管理者角色
操作系统管理计算机上软硬件资源。例如,操作系统对CPU、内存、磁盘等的管理,使得不同用户之间或者
同一用户的不同程序之间可以安全有序地共享这些硬件资源。那怎么让用户很好地利用这些硬件资源呢?就
是分块(parcel out),把硬件分块给应用程序使用。这里关键的原则是有效和公平,这是管理者的必备素
质。有效指的是不能浪费资源,公平指的是每个人都有可能享有资源,即不能有不公平的现象。当然真正的
公平是没有的事,这很像人类生活的现实。不过追求公平却是我们的本能,在虚拟世界里尽可能公平一点还
是非常应该的,至少应该是设计操作系统时的不懈追求。
图 1-5 操作系统就是一个魔术师(illusionist)
根据管理的资源不同,操作系统具体功能如下:
●CPU管理,即如何分配CPU给不同应用和用户。
●内存管理:即如何分配内存给不同应用和用户。
●外存管理:即如何分配外存(磁盘)给不同应用和用户。
●IO管理:即如何分配输入输出设备给应用和用户。
除了对上述资源进行管理和抽象外,操作系统作为掌控一切的软件系统,其自身必须是稳定和安全的,即操
作系统自己不能出现故障。因此,操作系统的设计还需包括如下两项:
●健壮性管理:即如何确保操作系统自身的正常运作。
●安全性管理:即如何防止非法操作和入侵。
为完成上面所列的功能,操作系统设计人员构思了许多机制。而所有这些机制均有其渊源,其背后隐含的是
人的哲学思维。本书就是要讲解操作系统背后的哲学原理,并依据这些哲学原理阐述操作系统是通过何种机
制、以何种方式完成上述列举的各种管理功能的。1.5 用户程序与操作系统
前面说过,操作系统上下分别是虚拟机器界面和物理机器界面。处于物理机器下面的是硬件,而硬件和操作
系统的关系将是本书的关注点。处于虚拟机器界面上面的是应用软件,应用软件和操作系统的关系不是本书
的重点,而是系统编程或底层编程等课程的关注点。在这里,我们只想来简要讨论一下应用程序和操作系统
的关系,因为这个关系对理解操作系统非常重要。
那么,操作系统和应用程序之间是什么关系呢?很显然,操作系统为用户程序提供了一个虚拟机器界面,而
应用程序运行在这个界面之上。但这个答案似乎太抽象,并不能帮助深入理解它们之间的关系。前面讲过,操作系统是一个程序,而用户程序也是程序,程序和程序之间能有什么关系呢?无非是调用和被调用的关
系。
那操作系统和用户程序之间到底谁是调用者,谁是被调用者呢?答案似乎很清楚:操作系统通过虚拟机器界
面为用户程序提供各种服务,用户程序在运行过程中不断使用操作系统提供的服务来完成自己的任务。例
如,用户程序在运行过程中需要读写磁盘,这个时候就需要调用操作系统的服务来完成磁盘读写操作;如果
需要收发数据包,也需要调用操作系统的服务来完成。当调用这些服务时,控制从用户程序转移到操作系
统,而操作系统在完成这些服务后将控制返回给用户程序。在这种思维模式下,用户程序是主程序,而操作
系统是子程序,如图1-6所示。
图 1-6 用户程序为主程序,操作系统为子程序
但是有正就有反,这就是哲学中的矛盾论。如果我们从另一个角度来看,会得出相反的结论。系统启动之后
最先启动的是什么程序?操作系统。用户程序不能在操作系统启用之前启动(除非是很厉害的病毒)。在此
之后,每次启动一个用户程序,都相当于操作系统将控制转移给用户程序;而在用户程序执行完毕后,控制
又回到操作系统。这样看上去,操作系统是主程序,它在一生当中不断调用各种应用程序,而每个应用程序
执行完之后再回到操作系统。就这样循环往复,直到无穷或机器关闭。在此种思维模式下,操作系统是主程
序,用户程序是子程序,如图1-7所示。
上述两种看法完全相反,但又似乎都有道理,有谁对谁错之分吗?没有。我们说过,人造学科没有对错之
分,只有好坏之分。你喜欢哪种观点就持那种观点,哪种观点帮助你理解操作系统,你就持那种观点。如果
两种观点都有帮助,你可同时持有两种观点。图 1-7 操作系统为主程序,用户程序为子程序
当然,上述关系的描述是非常简单化的。实际上,操作系统和各种用户程序可以看做互相调用,从而形成一
个非常复杂的动态关系。了解并阐述这种复杂的动态关系就是本书的目的。1.6 操作系统的范畴
前面介绍了操作系统的两个角色:魔术师和管理者。这两个角色之间既有区别,又有联系。为了完成不同的
任务,操作系统有时需要扮演魔术师的角色,有时需要扮演管理者的角色,有时则需要同时扮演这两个角
色。那么操作系统要完成的任务具体有哪些呢?前面提到过:
●CPU管理,即如何分配CPU给不同应用和用户。
●内存管理:即如何分配内存给不同应用和用户。
●外存管理:即如何分配外存(磁盘)给不同应用和用户。
●IO管理:即如何分配输入输出设备给应用和用户。
CPU管理就是将要介绍的进程管理。进程管理的主要目的有3个:第一个是公平,即每个程序都有机会使用
CPU。第二个是非阻塞(non-blocking),即任何程序不能无休止地阻挠其他程序的正常推进。如果一个程
序在运行过程中需要输入输出或者因别的什么事情而发生阻塞,这个阻塞不能妨碍别的进程继续前进。就像
人类世界,缺了谁地球照样旋转。第三个是优先级。在人类生活中人的地位不完全一样,地位高的就比地位
低的优先级高。人类把自己生活中的这种关系搬到操作系统里面,就有了优先级的概念,即某些程序比另外
一些程序优先级高。如果优先级高的程序开始运行,则优先级低的程序就要让出资源。就像我们经常说的,我们坚决反对大锅饭,应该让一部分人(程序)先富起来。
内存管理主要是管理缓存、主存、磁盘、磁带等存储介质所形成的内存架构。为此目的,操作系统设计人员
发明了虚拟内存的概念,即将物理内存(缓存和主存)扩充到外部存储介质(磁盘、光盘和磁带)上。这样
内存的空间就大大地增加了,能够运行的程序的大小也大大地增加了。内存管理的另一个目的是让很多程序
共享同一个物理内存。这就需要对物理内存进行分割和保护,不让一个程序访问另一个程序所占的内存空
间,专业术语称为运行时不能越界。在生活中,就是我家的东西不希望你跑来拿。
外存管理通常也称为存储管理,它就是众所周知的文件系统了。文件系统的主要目的是将磁盘变成一个很容
易使用的存储媒介以提供给用户使用。这样我们在访问磁盘时无须了解磁盘的物理属性或数据在磁盘上的精
确位置,诸如磁道、磁柱、扇面等。当然,文件系统还可以建立在光盘和磁带上。只是使用最为频繁的文件
系统都以磁盘为介质。
IO管理也称为设备管理,就是管理输入输出设备。IO管理的目的有两个:一是屏蔽不同设备的差异性,即
用户用同样的方式访问不同的设备,从而降低编程的难度;二是提供并发访问,即将那些看上去并不具备共
享特性的设备(如打印机)变得可以共享。
另外还有一个任务称为批处理,它提供一种无需人机交互的程序运行模式。有时我们不需要人来交互,就交
给计算机批处理。主要目的是达到吞吐量最大化,单位时间完成的任务最多。图1-8描述的是操作系统的5个
核心功能。
当然,在真实的操作系统里,上述5个核心部件不一定界限分明,甚至它们不在同一个态势下运行(本书后
面将说明这一点)。图1-9描述的是Windows操作系统简化了的结构。
图 1-8 操作系统的5个核心功能图 1-9 Windows操作系统简化结构图1.7 为什么学习操作系统
到目前为止,本书论述了操作系统的定义、主要任务以及操作系统与用户程序的关系,读者可以体会到操作
系统的重要性。但仅仅是因为操作系统重要就要学习它吗?世界上重要的东西太多了,难道我们都要学吗?
即使是计算机专业的学生,不学操作系统也照样可以编程写软件。那我们为什么要学呢?当然我们有一千个
理由要学,但这里仅列出了几个。
首先,操作系统的功能应用于很多领域。如果开发并发程序:Web Service、分布式系统和网络,你会发
现,这些领域大量使用了操作系统的概念和技术。如果你学好了操作系统,你就可以对你做的事情更加有信
心。
其次,操作系统的技巧也应用于很多领域,如抽象、缓存、并发等。操作系统简单来说就是实现抽象:进程
抽象、文件抽象、虚拟存储抽象等。而很多领域也使用抽象。如数据结构和程序设计就大量使用了抽象,记
得抽象数据类型吗?记得抽象类吗?很多地方都用缓存。你开发Web应用要不要缓存呢?这些你都需要。如
果学习操作系统,你就掌握了这些知识。触类旁通,你学习别的知识时就容易多了。
不过最重要的理由并不是上面的两条,而是操作系统真的很有趣。对于一个计算机专业的学生来说,难道不
想知道自己写的程序如何在计算机上运行吗?读者一定见过汽车吧。汽车前面那个盖子叫前盖(hood)。很
多人买车后第一件事是什么?打开前盖。那么打开前盖看到的是什么东西?马达、变速箱。为什么第一件事
要打开前盖呢?因为好奇这辆汽车是怎么开动的(见图1-10)。
图 1-10 学习操作系统就是揭开覆盖在计算机上的“前盖”
那么对于一个程序员来说,有没有在看到一台计算机的时候,想过为什么计算机能进行计算?有没有买来一
台新计算机后就打开盖子呢?多数人恐怕没有打开过计算机外壳。不过,没有打开过也不用遗憾。因为即使
你把计算机后盖打开,还是不能明白计算机是怎么运转的,此时只看到一堆硬件:芯片、主板、布线等,而
这些硬件并不会告诉你太多有关计算机运转的信息。如果真的想知道计算机是怎么运转的,你就得学习操作
系统。当然,如果你想知道计算机在硬件层面上是如何运转的,则还应该学习计算机组成和体系结构等课
程。
虽然学习操作系统很有趣,但并不是所有人都有这样的感觉。历史证明,对很多人来说,学习操作系统是一
件很痛苦的事情。不过我希望阅读本书对读者来说是一件乐事,难道窥探奥秘不是一件激动人心的事吗?思考题
1.什么是操作系统?请用一句话描述你对操作系统的理解。
2.你对操作系统和用户程序之间的关系有何看法?阐述你的想法。
3.简要列出操作系统覆盖的范畴及每个范畴的核心内容。
4.你为什么要学习操作系统?与本书列出的理由相同吗?简要阐述你的动机。
5.操作系统要对不同的部件进行管理,请论述这些管理之间的异同点。
6.设备管理要达到的目的是什么?
7.有人说设备管理软件(设备驱动程序)因为经常由第三方提供,因此不应该作为操作系统的一部分。你对
此有何看法?你认为应该如何判断一个软件是否属于操作系统?
8.请列出程序执行过程中操作系统的介入情况。
9.说操作系统是人造学科,根据是什么?
10.人造学科的特点是什么?它对我们学习操作系统有何帮助?
11.OS需要编译器来编译,而编译器的运行需要OS来支持,那到底是谁先出现谁后出现呢?第2章 操作系统历史
引子:不能承受之真
20世纪末21世纪初,美国兴起了励志演讲(motivational speech)大潮,各种人等乐此不疲。在这拨励志大潮
中,出现了多名影响力广泛的励志演讲家。这些演说家所到之处,真是万人空巷,人潮涌动,场面之壮观令
人叹为观止。
其中一位演讲家由于其名望很高接受了电视台采访。
记者:“您在励志演讲领域声名远扬,影响巨大,您的每场演讲都爆满,能否请您阐述一下什么是励志演
说?”
励志演讲家:“你想知道吗?告诉你,我跟你一样,我压根就不知道什么是励志演讲。我只知道励志演讲非
常流行,我只不过是利用这个潮流来赚钱而已。既然大家都喜欢,我就讲,至于我讲的东西是什么意思,我
根本不知道。但是听众很喜欢!”
我想起了一句英语歌谣:sometimes when we touch, the honest is too much!(有时,当我们拥抱时,所感受
的诚实太过分)。也许人们都不喜欢真实,于是成就了很多人在论述操作系统历史(甚至人类历史)时的粉
饰太平。
操作系统的演变就是我们对计算机硬件进行粉饰的过程。
操作系统进化的推动因素
大多数的教材都专门有一章谈论相关领域的历史,操作系统自然也不例外。不过不同的教材谈论历史的目的
却又不同。多数教材是为了铺垫一下本学科的发展背景,让学生了解相关领域里的发展大事,并没有将历史
与现实的发展联系起来。本书谈论的历史则是以史明鉴,不是为了谈论历史而谈论历史,而是为了让学生明
白操作系统为什么是现在这个样子,以及将来会是什么样子。从根本上把握操作系统这一计算机领域核心学
科的脉搏,深刻理解社会变迁给计算机这门人造学科带来的不可抵挡的变化。同时,我们还将揭示计算机发
展史上一些鲜为人知的重要细节,给学生一个窥探全貌的快感。
如前面所述,操作系统的不断发展与改善由两个因素驱动:
●硬件成本不断下降。
●计算机的功能和复杂性不断变化。
就是这些因素决定了操作系统的历史,我们一定要牢牢掌握这两个趋势。一是硬件成本不断降低,就以硬盘
为例,IBM制造的第一张硬磁盘直径达到2米,造价100多万美元,而容量仅仅1MB,而现在一个容量100GB
的硬盘成本只有几十美元。当然,过去的硬盘和今天的硬盘的制造技术完全不同,第1张硬盘的质量坚挺,可以当做咖啡桌使用,而现在的硬盘(指盘片)非常软,根本不能承受重物。二是计算机复杂性不断增加。
这一点对于很多人来说并不感到惊奇。人类做的任何事情,都是越来越复杂。你不整理住的地方很快就乱
了,有没有这种经验?当然,你的生活随着年龄的增长,也会越来越复杂。最初,计算机的组件虽然巨大,但数量少,且功能简单,现在,一台计算机里面包括的元件数量实在是太多了。
硬件成本的下降和计算机复杂性的提高就推动了操作系统的演变。成本降低意味着同样的价格可以买到更先
进的计算机。而复杂性提高自然需要操作系统的能力也得提高。就是这些变化使得操作系统从最初的仅仅几
百或几千行代码的独立库函数,发展到今天多达4000万行代码的操作系统(如Windows XP),而某些Linux
的版本的代码行数更加庞大。
操作系统之所以越来越复杂是因为硬件质量和数量的提升使得操作管理的东西增多,而且人类永不满足的各
种越来越苛刻的要求也使得计算机操作系统的复杂性增加。
另外,还有另外一个附加因素影响着操作系统的发展,这就是操作系统和攻击者之间的博弈。这个世界上总
有些人想利用计算机的缺陷来进行各种损人利己或损人又不利己的活动。操作系统在最初设计时根本就没有
想到会有人从事破坏活动。大概因为最早的计算机工作者认为能够达到使用计算机水平的人都是好人,无需
设计任何安全机制。这样,在后来发现有人试图利用计算机进行不良操作时,就迫不得已修改操作系统,使
其具有安全上的防范功能。每当操作系统改进了安全性,攻击者也会改良他们的攻击手段,这样循环往复,造就操作系统安全水平和攻击者攻击水平不断交替上升。
下面我们就来说一说操作系统是如何因上述驱动因素的变化而变化的。2.1 第一阶段:状态机操作系统(1940年以前)
这是计算机处在萌芽时期出现的操作系统。这种操作系统运行在英国人巴贝斯(Babbes)想象中的自动机
中。所谓状态机操作系统实际上算不上是我们现在通常所定义的操作系统,而是一种简单的状态转换程序:
根据特定输入和现在的特定状态进行状态转换而已。这个时候的计算机也不是现代意义上的计算机,而是所
谓的自动机,其功能非常简单,可以用原始来形容。能做的计算也只限于加减法。这个时代的操作系统没有
什么功能,不支持交互命令输入,也不支持自动程序设计,甚至这个时候还没有存储程序的概念。
驱动这一阶段操作系统的动力是个人英雄主义。因为此时尚无任何计算机工业、计算机研究及计算机用户。
计算机及其操作系统的发展完全是某些人的个人努力。
这个阶段因为计算机刚刚出现,没有多少人能够接触到计算机,自然不存在什么安全问题。
这个阶段没有操作系统。如果非要说有的话,人就是这个时代的操作系统:因为自动机的一切动作均是人在
操控的。2.2 第二阶段:单一操作员单一控制端操作系统(20世纪40年代)
这种单一操作员单一控制终端(Single Operator, Single Console, SOSC)的操作系统是在刚出现计算机时人们
能想到的最直观的控制计算机的方式。这个时候的代表机型为美国宾夕法尼亚大学与其他机构合作制作的
ENIAC计算机。这是第一台电子计算机,但不是第一台计算机。在这之前有个英国人造了一部机械计算
机,通过手柄摇动进行计算。在ENIAC刚造出来的时候,谁都不知道计算机是怎么回事,所以没有操作系
统的整体概念,唯一能想到的就是提供一些标准命令供用户使用,这些标准命令集合就构成了我们的原始操
作系统SOSC。
SOSC操作系统的设计目的是满足基本功能,并提供人机交互。在这种操作系统下,任何时候只能做一件
事,即不支持并发和多道程序运行。操作系统本身只是一组标准库函数而已。操作系统本身并不自我运行,而是等待操作员输入命令再运行。用户想使用什么服务,就直接在命令行键入代表该服务的对应操作系统的
库函数名(文件名)即可。这种操作系统的资源利用率很低:你输入一个命令就执行一个库函数,拨一下动
一下。当操作员在思考时或进行输入输出时,计算机则安静地等待。当然了,从人的角度来看,效率并不
低,你键入什么,计算机就立即执行什么。但从机器的角度考虑,因为时刻都等着人相对较慢的动作,效率
就太低了。
由于这个时代的计算机很稀少,整个世界也只有几台,而人却不是,提高计算机的利用率就变得十分重要。2.3 第三阶段:批处理操作系统(20世纪50年代)
为了提高单一操作员单一控制终端的操作系统SOSC的效率,人们提出了批处理操作系统。在仔细考察了
SOSC后,人们发现,SOSC效率之所以低下,是因为计算机总是在等待人的下一步动作,而人的动作总是很
慢。因此,人们觉得,如果去掉等待人的时间,即让所有的人先想好自己要运行的命令,列成一个清单,打
印在纸带上,然后交给一个工作人员来一批一批地处理,效率不就提高了吗?这样就形成了批处理操作系
统。
批处理操作系统的代表、第二代通用计算机IBM的1401和7094等,就是这样通过减少人机交互的时间而达到
CPU和输入输出利用率的改善。批处理的过程是:用户将自己的程序编在卡片或纸带上,交给计算机管理员
处理。管理员在收到一定数量的用户程序后,将卡片和纸带上的程序和数据通过IBM 1401机器读入,并写
到磁带上。这样每盘磁带通常会含有多个用户的程序。然后,计算机操作员将这盘磁带加载到IBM 7094
上,一个一个地运行用户的程序,运行的结果写在另一个磁盘上。所有用户程序运行结束后,将存有结果的
磁盘取下来,连到IBM 1401机器上打印结果,然后就可以将打印结果交给各个用户了。
很显然,在批处理下,操作系统的功能和复杂性均得到提升。在SOSC环境下,每个用户自己控制程序的开
始和结束。而在批处理下,很多用户的程序一个接一个地存放在磁带上,用户本人并不在场,无法自己控制
程序的开始和结束。而这个任务就交给了批处理操作系统。负责这个任务的操作系统功能就称为批处理监视
器(batch monitor)。而整个批处理操作系统就是由批处理监视器和原来的操作系统库函数组成的,如图2-1
所示。
图 2-1 SOSC和批处理操作系统比较
批处理监视器的功能就是按部就班地执行用户的程序。这个时代的操作系统仍然只能在同一时间执行一个程
序,但此时文件的概念已经出现。之前在SOSC诞生时期没有文件的概念。为什么到批处理时期出现了文件
的概念呢?因为磁带上的多个用户程序必须以某种方式进行隔离,这需要一个抽象的东西来区分。这个抽象
的东西不是别的,就是文件。除了文件管理外,此时的操作系统还能够管理读卡机、磁带、打印机等。此种
操作系统的任务就是加载一个程序、运行、打印结果,然后执行下一个程序。批处理操作系统的两个部分的
关系也很清楚:一部分是控制程序执行,一部分是支持程序执行。
批处理操作系统的重要代表有IBM开发的FORTRAN监视系统FMS,用于IBM 709;IBM开发的基于磁带的
工作监控系统IBSYS,用于IBM 7090和7094;以及密歇根大学开发的UMES(密歇根大学执行系统),用于
IBM 7094。
密歇根大学执行系统(UMES):操作系统的黎明
在当时,世界上最先进的计算机是IBM 7094。作为礼物,IBM分别给密歇根大学(UM)和麻省理工学院
(MIT)各捐赠了一台。密歇根大学坐落在密歇根湖和伊犁湖旁,麻省理工学院紧邻大西洋。IBM的高管喜
欢搞帆船比赛。每次搞帆船比赛都需要使用计算机来安排赛程、计算成绩、打印名次等。因此,IBM在捐赠
机器给UM和MIT时有一个要求:平时归学校使用(MIT的机器还需要与新英格兰周围的学校如达特茅斯学
院等共享),一旦进行帆船比赛就得停下一切计算任务为IBM服务。这当然使得学校很恼火。因为那个时候
很难在程序执行中间停下来,将中间结果保留等以后再执行。只要停下来,就要从头再来。
于是,密歇根大学的R.M.Graham、Bruce Arden和Bernard Galler在1959年开发出了当时著名的MADUMES系
统,即密歇根算法译码器和密歇根大学执行系统。密歇根算法译码器是一种可扩展的程序设计语言,而密歇
根大学执行系统是一个能够保存中间结果的操作系统。有了这个系统,密歇根大学的计算机运行基本上不受
IBM帆船比赛所造成的中断的影响。MIT在知道这个系统后,将其安装到自己的7094机器上。MAD编程语
言随后又进一步移植到Philco、Univac和CDC等机器上,其很多功能后来被加入到FORTRAN语言里。驱动这个阶段操作系统发展的动力是改善效率。因为机器的昂贵,我们不能容忍机器在操作员思考或IO设
备工作期间闲置起来。2.4 第四代:多道批处理操作系统(20世纪60年代)
虽然批处理操作系统无需人机交互过程就能在一定程度上提高计算机的效率,但还是不那么令人满意。因为
CPU和IO设备的运行是串行的,即在程序进行输入输出时,CPU只能等待。CPU需要不断地探询IO是否完
成,因而不能执行别的程序。
由于IO设备的运行速度相对于CPU来说实在太慢,这种让高速设备等待低速设备的状况令人颇感痛心。人
们又想,能否将CPU和IO进行并发呢?即在一个程序输入输出时,让另一个程序继续执行。换句话说,能
否将CPU运行和IO设备的运行重叠起来而改善整个系统的效率呢?答案是肯定的,不过需要付出代价。因
为CPU和IO重叠需要我们将多个程序同时加载到计算机内存里,从而出现了多道批处理操作系统。
在多道批处理操作系统时代,同一时间可以运行多个程序(宏观上),但控制计算机的人还是一个,即用户
将自己的程序交给计算机管理员,由管理员负责将用户的程序加载到计算机里并执行。由于多个程序同时执
行,因此操作系统需要能够在多个程序(工作)之间进行切换,并且能够管理多个IO设备,同时还需要能
够保护一个进程不被另一个进程干扰。
显而易见,操作系统的功能和复杂性都比简单批处理时复杂得多:既要管理工作,又要管理内存,还要管理
CPU调度。
OS360(M):划时代的多道批处理操作系统
典型的多道批处理操作系统是IBM的OS360(M),它由密歇根大学为IBM公司开发(这是该操作系统名称
后面的M所代表的意义)。它运行在IBM的第三代计算机System360、System370、System 4300等上。
OS360在技术上和理念上都是划时代的操作系统,引进了内存的分段管理,但在商业上没有获得广泛使
用。因为它有很多错误。这些错误很难避免,划时代、崭新的东西很难一次做到完美。尽管如此,OS360
还是被公认为一个划时代的操作系统,它同时支持商业和科学应用,而之前的操作系统只能支持科学计算。
IBM随后对OS360(M)进行了改进,使其逐渐演变为一个功能强大、性能可靠的操作系统。这个改进的版
本被命名为OS390。该操作系统提供了资源管理和共享,允许多个IO同时运行,以及CPU和磁盘操作可以
并发。390获得了广泛的商业应用,一直到今天。
驱动这个阶段操作系统发展的动力仍然是改善效率。因为机器的昂贵,我们不能容忍机器(CPU)在IO设
备工作期间闲置起来。同时,我们对计算机的要求也开始多起来。因此,这个阶段还伴随着对用户不断增长
的要求进行满足。2.5 第五代之一:分时操作系统(20世纪70年代)
多道批处理操作系统的出现使计算机的效率(主要是吞吐率)大大提高。不过这时人们又提出了另外一个问
题:将程序制作在卡片上交给计算机管理员来统一运行,将使得用户无法即时获知程序运行的结果。而这是
一个大问题。想想如果你编写了一个程序,却需要让别人去运行,并等上若干天才能知道结果,这个滋味显
然不好受。万一计算机管理员疏忽了,忘记运行你的程序,或者操作错误,导致程序丢失,情况就更加糟
糕。
基于上述原因,人们考虑能否让人回到计算机前面来,每个人自己管自己的程序,但是,大家的程序可以同
时运转。人的因素又引了回来。这看上去与原始的SOSC似乎一样,但有个关键的不同:多个人同时连在计
算机上,每个人看做另外的一个IO终端而已。每个用户拥有一个终端显示器,这些终端显示器经过RS232
穿行线缆与计算机连接。终端显示器只能接收和发送文本命令和信息。计算机在所有连接的终端用户之间进
行分时,即分给每个人有限的时间,只要时间到了,就换一个进程。这种时分切换下的操作系统就是分时操
作系统。
在分时操作系统下,任意时间可以运行多个程序,且用户直接与计算机交互,当场调试程序。这就和单一操
作员单一终端不一样了,从人本转成了物本。在单一操作员单一终端的情况下,一切等着人。以前执行一条
命令就等人,分时系统就是人等机器。这个模型带来一个直接的结果,就是机器不再等你,等你想问题时机
器就切换到别的程序,等你想好了机器我再切换回来,接受你的输入。就这样,计算机就在很多人之间来回
转,你敲个命令就响应,然后切换走。如果时间掌握得好,用户输入完一个命令计算机正好回来,用户就无
需等待。当然,如果一个用户打字速度足够快,可能会觉得计算机慢;如果打字速度非常慢,就有可能觉得
计算机很快。不同的人感觉有可能完全不同。
显然,和前面几代的操作系统比,分时操作系统要复杂得多。相比于多道批处理系统,最主要的变化是资源
的公平管理。在多道批处理下,公平不公平没有人知道。大家交了工作后只管回家等结果。至于自己的程序
排在谁前谁后,抑或占用了多少CPU时间是无关紧要的。现在,大家都坐在计算机显示终端前面,任何的不
公平将立即感觉到。因此,公平的管理用户的CPU时间就变得非常重要。除此之外,池化(pooling)、互
斥、进程通信等机制相继出现,使得分时操作系统的复杂性大为增加。
傲慢的代价:MULTICS操作系统
分时操作系统里面最著名的应该是MULTICS和UNIX。前面讲过,IBM在其捐赠7094给UM和MIT时附加了
一些条件,而这些附加条件使得学校非常恼火,但又不能拒绝(想想别的学校吧,他们连这种恼火的机会都
没有)。为此,UM开发了UMES系统以应对这个问题。MIT则将UMES移植到了自己的7094中。后来大家觉
得只保存中间结果还不是最好的办法,毕竟频繁地保存中间结果等帆船比赛结束后再进行重载仍存在麻烦,于是就想开发一个可支持多用户的分时操作系统,以便一劳永逸地解决这个问题。这个时候MIT想到了密歇
根的R.M.Graham,将其请来。在R.M.Graham的主持下,来自贝尔实验室、DEC(Digital Equipment
Corporation,美国数字仪器公司)和MIT的设计人员同仇敌忾(针对IBM的傲慢),一起努力,开始了
MULTICS分时操作系统的研制。
不过,在MULTICS还没有开发出来时,开发团队内部出现了分歧,贝尔实验室的几个人越来越看不惯DEC
和MIT的人,觉得这伙人的思维方式跟自己不一样,做的东西不专业,觉得和他们一起做研究把自己的水平
降低了,就自立门户,搞出了UNIX,并因此获得图灵奖。而UNIX的出现,使得MULTICS从一面世,就不
能挺立,真是中国历史上“既生瑜,何生亮”在计算机操作系统历史上的完美演绎。不过,MIT最后还是做出
了一个应用于部分商用领域的分时操作系统CTSS(Compatible Time Sharing System)。而DEC公司则做出了
非常成功的VMS操作系统。
分时操作系统通常运行在第三代计算机PDP、VAX和CRAY上,其中PDP、VAX是DEC公司生产的,不过
DEC已经不复存在。CRAY是CRAY公司生产的。
驱动这个阶段操作系统发展的动力是响应时间和对越来越多资源的管理。因为机器的昂贵,我们不能容忍机
器(CPU)在IO设备工作期间闲置。同时,因为人的时间宝贵,我们不能容忍人们坐在机器前漫长等待。
因此发明了分时操作系统来解决这两个问题。因为分时引入的多道程序设计,又造成操作系统的空前复杂,我们需要应对竞争、通信、死锁、保护等一系列的新功能。因此,操作系统在本阶段变得相当复杂。2.6 第五代之二:实时操作系统
随着人类技术的进步,计算机得到了广泛应用。其中的一种应用称为进程控制系统,即使用计算机监控某些
工业进程,并在需要的时候采取行动。所有这些系统都具备一个特点:计算机对这些应用必须在规定时间内
做出响应,否则有可能发生事故或灾难。例如,在工业装配线上,当一个部件从流水线上一个工作站流到下
一个工作站时,这个工作站上的操作必须在规定时间内完成,否则就有可能造成流水线瘫痪,而影响企业的
生产和利润。又例如,在导弹防卫系统中,对来袭导弹的轨迹计算必须在规定时间内完成,否则就可能被来
袭导弹击中而无法做出反应。其他对计算机响应时间有要求的系统包括核反应堆状态监视系统、化学反应堆
监视系统、航空飞行控制系统等。
这种对计算机响应时间有要求的系统通常称为临界系统或应用。而为了满足这些应用对响应时间的要求,人
们开发出了实时操作系统。实时操作系统是指所有任务都在规定时间内完成的操作系统,即必须满足时序可
预测性(timing pre-dictability)。需要注意的是,实时系统并不是指反应很迅速的系统,而是指反应具有时
序可预测性的系统。当然了,在实际中,实时系统通常是反应很迅速的系统。但这是实时系统的一个结果,而不是其定义。
显然,实时操作系统的最重要部分就是进程或工作调度。只有精确、合理和及时的进程调度才能保证响应时
间。当然,对资源的管理也非常重要。没有精密复杂的资源管理,确保进程按时完成就成了一句空话。另
外,基于其使用环境,实时操作系统对可靠性和可用性要求也非常高。如果在这些方面出了问题,时序可预
测性将无法达到。
实时系统通常又分为软实时系统和硬实时系统。软实时系统在规定时间得不到响应所产生的后果是可以承受
的,如流水装配线。即使装配线瘫痪,也只是损失了资金;而硬实时系统在得不到实时响应后则可能产生不
能承受的灾难,如导弹防卫系统。如果反应迟钝,结果就可能是严重损失。
商用实时操作系统的代表有VxWorks和EMC的DART系统。2.7 第六代:现代操作系统(1980年以后)
在20世纪80年代后期,计算机工业获得了井喷式的发展。各种新计算机和新操作系统不断出现和发展,计算
机和操作系统领域均进入了一个百花齐放、百家争鸣的时代。尤其重要的是工作站和个人机的出现,使计算
机大为普及。独享计算机也可以负担得起。这个时候的操作系统代表有:DOS、Windows、UNIX、Linux和
各种主机操作系统,如VM、MVS、VMS等。DOS、Windows、UNIX、Linux通常称为开放式系统操作系
统,分别运行在PC机、VAX和Workstation上。操作系统也重新回到子函数库的状态。
随着硬件越来越便宜,个人机出现在人们的视野中。人们可以拥有自己的计算机,而无需与他人分享。在刚
刚出现个人机的时候,拥有个人机的人感觉很好,而那些需要与别人共享小型机的人则感觉不好。由于个人
机由用户一个人独享,分时操作系统的许多功能就无须存在。因此,个人机操作系统又变回到了标准函数库
系统。这时最著名的当属DOS、Windows 3X、苹果机操作系统(Mac OS)等。
但在独享了一阵个人机后,人们发现,没有分时功能的操作系统使一些事情无法完成。这是因为,虽然只有
一个人在使用机器,但这个人可能想同时做好几件事,例如,同时运行好几个程序,没有分时功能这是不可
能的。于是,人们觉得需要对个人机操作系统进行改善,将各种分时功能又加入了操作系统。
这时候就需要对程序进行保护,因为现在运行多个程序。虽然都是你的东西,但是也不能混淆。于是,Windows NT出现了,Xenix出现了,Ultrix出现了。
这个时候的另外一个特征是网络的出现。网络促进了网络操作系统和分布式操作系统的出现。对于网络操作
系统来说,其任务是将多个计算机虚拟成一个计算机。传统的网络操作系统是在现有操作系统的基础上增加
网络功能,而分布式操作系统则是从一开始就把对多计算机的支持考虑进来,是重新设计的操作系统,所以
比网络操作系统效率高。分布式操作系统除了提供传统操作系统的功能外,还提供多计算机协作的功能。2.8 操作系统的演变过程
计算机操作系统的演变可以分为三条发展线索,分别是主机操作系统、服务器操作系统和个人机操作系统。
图2-2简略地表示了这三条线索上操作系统的演变历史。
图2-2最左面的3列代表主机操作系统的演变,最右面的两列代表个人机操作系统的演变,中间列出了服务器
操作系统的演变。当然,到最后,这三大块的界限也不是很清晰。
图 2-2 操作系统的历史演变
主机操作系统的演变从输入输出控制系统IOCS和IBSYS开始,经历OS360的里程碑式的突破,逐步演变为
VS、MVS和VM三个系列(其中VM系列还吸取了UMES和CTSS的某些特征)。目前IBM是这三个系列的开
发商和运营商,其VM操作系统经历多代后已经变得十分可靠。美国大型金融证券公司都在使用它们。
服务器操作系统的演变从UMES开始,经CTSS演变为IBM的MVS和VM操作系统,经MULTICS演变为UNIX系统。在20世纪80年代初,UNIX一分为二:由AT&T(美国电话电报公司)提供的System系列和由UCB提
供的BSD系列。XENIX为微软公司为PC机而移植的AT&T版的UNIX操作系统。AT&T是UNIX的鼻祖,UCB则在美国国防部的支持下开发了BSD(伯克利软件分配)系列。
IBM和斯坦福大学看到AT&T和UCB的UNIX软件后,也不甘示弱,分别研发了AIX和SUN OS(SUN是
Stanford University Networks(斯坦福大学网络)的缩写)。这样UNIX就形成了4个系列:AT&T的System系
列、IBM的AIX系列、SUN的SUN OS系列以及UCB的BSD系列。
20世纪90年代中期,在美国国防部停止对BSD的支持后,UCB亦停止了BSD系列的研发,而AT&T也在与
BSD焦头烂额的较量中放弃了System系列。Linux则趁AT&T和UCB忙于与对方较量的时候发展起来。卡内
基梅隆大学(Car-negie Mellon University)在看到UCB和斯坦福大学都研发了UNIX后,慌忙开发了个
MACH操作系统。MACH为微内核操作系统,在学术界得到了一定的使用,但由于其运行效率低下而没有获
得商业上的广泛应用。这样UNIX的商业使用版本就剩下AIX、SOLARIS系列(SUN OS的后续版本)和
Linux系列。后来由于惠普公司(HP)加入到服务器行列使得UNIX家族又增加了一个版本:HP-UX。在
UNIX家族中,SUN公司濒临灭亡的命运令SOLARIS的前途堪忧。
个人机操作系统的演变可以说是从DOS开始的。微软公司在1980年以100美元的成本买断了DOS的版权。而
DOS的功能很简单:文件没有文件夹,所有文件都保存在同一个地方,谁都可以删除操作系统。当然那时也
没有那么多人从事破坏活动。在看到苹果公司的Mac OS的图形界面后,微软公司给DOS增加了一个图形界
面,称为Windows。Windows在发展了几个版本后,到Windows 98时,微软公司改变了战略。因为到当时为
止,所有的Windows并不是真正的操作系统,而是覆盖在DOS上的一个用户图形界面,并不支持多道编程。
微软高管比尔·盖茨亲自打电话给DEC的David Cutler,请其过来主持新一代Windows操作系统的研发工作。
David Cutler是DEC公司VMS操作系统的主要设计人员。他从DEC带过来一批人到微软公司工作,设计出了
Windows NT操作系统。这是一个真正的支持多道编程的操作系统。Windows NT继承了VMS的优良结构和
Windows 3X的图形界面,在一推出就获得了市场的认可。Windows NT经过几代演变,成为现在的Windows
Vista。Windows操作系统系列也从单一的支持个人机演变为支持个人机和服务器的“双料”操作系统。
操作系统的分类
操作系统基本上可以分为:主机操作系统,如OS260、OS390、CTSS;服务器操作系统,如UNIX、Windows 2000、Linux;多CPU计算机操作系统,如Novell Netware;个人计算机操作系统Windows 2000、Windows XP、Mac OS;实时操作系统,如VxWorks、DART;嵌入式操作系统,如Palm OS、Windows
CE、Android、Symbian等。
同一台计算机可以运行不同的操作系统,而同一个操作系统也可以运行在不同的计算机上。例如,个人机上
可以运行的操作系统包括DOS、Linux、NeXTSTEP、Windows NT、SCO UNIX等DEC VAX计算机上可以运
行的操作系统有VMS、Ultrix-32、BSD UNIX等。UNIX操作系统可以运行在XENIX 286、APPLE AUX、CRAY-YMP、IBM 360370等计算机上;Windows NTXP可以运行在Intel 386和Itaninum、DEC的Alpha、摩
托罗拉的PowerPC和MIPS计算机的MIPS上。
当然,运行在不同机器上的UNIX版本并不一样,例如运行在IBM 360370上的UNIX是Amdahl UNIX
UTS580和AIXESA,而运行在CRAY-YMP计算机上的UNIX是AT&T System V。2.9 操作系统的未来发展趋势
随着计算机不断普及,操作系统的功能会变得越来越复杂。在这种趋势下,操作系统的发展将面临两个方向
的选择:一是向微内核方向发展,二是向大而全的全方位方向发展。微内核操作系统虽然有不少人在研究,但在工业界获得的承认并不多。这方面的代表是MACH系统。在工业界来说,操作系统是向着多功能、全方
位方向发展。Windows XP操作系统现在有4000万行代码,Windows 7的代码规模更大,某些Linux版本有2亿
行代码,SOLARIS的代码行数也在不断增多。鉴于大而全的操作系统管理起来比较复杂,现代操作系统采
取的都是模块化的方式,即一个小的内核加上模块化的外围管理功能。
例如最新的SOLARIS将操作系统划分为核心内核和可装入模块两个部分。其中核心内核分为:系统调用、调度、内存管理、进程管理、VFS框架、内核锁定、时钟和计时器、中断管理、引导和启动、陷阱管理、CPU管理;可装入模块分为:调度类、文件系统、可加载系统调用、可执行文件格式、流模块、设备和总线
驱动程序等。
最新的Windows将操作系统划分成内核(kernel)、执行体(executive)、视窗和图形驱动和可装入模块。
Windows执行体又划分为:IO管理、文件系统缓存、对象管理、热插拔管理器、能源管理器、安全监视
器、虚拟内存、进程与线程、配置管理器、本地过程调用等。而且,Windows还在用户层设置了数十个功能
模块,可谓功能繁多,结构复杂(见图2-3)。
图 2-3 Windows 2000XP2003系统结构(来源:参考文献[8])
进入21世纪以来,操作系统发展的一个新动态是虚拟化技术和云操作系统的出现。虚拟化技术和云操作系统
虽然听上去有点不易理解,它们不过是传统操作系统和分布式操作系统的延伸和深化。虚拟机扩展的是传统
操作系统,将传统操作系统提供的一个虚拟机变成多个虚拟机,从而同时运行多个传统操作系统;云操作系
统扩展的是分布式操作系统,而这种扩展有两层意思:分布式范围的扩展和分布式从同源到异源的扩展。虚
拟机技术带来的最大好处是闲置计算资源的利用,云操作系统带来的最大好处是分散的计算资源整合和同
化。2.10 讨论:操作系统虚拟化和虚拟化的操作系统
随着虚拟化及云计算等技术的出现和不断演变,人们心目中的各种传统计算技术、模型和理论都在发生改
变。操作系统作为计算机的核心系统软件,其面临的调整或挑战可能更为深刻,也更为细腻。有人断言,虚
拟化将迫使操作系统退出历史舞台,因为操作系统的功能将由虚拟机来替换。但情况的发展似乎并没有为这
种观点提供佐证。
不论从管理者的角度看,还是从魔术师的角度看,虚拟机本身就是一个操作系统,只要虚拟机在运行,操作
系统就在运行,只不过更换了一个名字而已。因此,所谓的操作系统将退出历史舞台一说实属偷换概念。当
然,虚拟机与传统的操作系统有所不同,虚拟机设计的侧重点、功能范畴、某些功能的实现哲学并不完全等
同于传统的操作系统。也许,那些声称操作系统将退出历史舞台的人指的是传统的非虚拟机操作系统。
事实上,传统的操作系统也不会退出历史舞台。不过,其在虚拟化时代发挥作用的方式有可能发生变化。有
迹象表明,传统操作系统扮演的角色在全虚拟化环境下有所收敛并出现专攻趋势。例如,一种已经露出端倪
的倾向是将应用软件和操作系统打包发布,即应用程序与其赖以运行的操作系统的部分功能作为一个软件包
发布出来。用户运行软件时不再需要先安装操作系统,只需要安装一个虚拟机即可。这样不同的软件包可以
打包不同的操作系统,用户无需因为购买了不同的软件而需要安装不同的操作系统。根据应用软件的具体情
况,被打包的操作系统功能部分可能很小,也可能较大,但由于一个应用软件常常不会用到一个传统操作系
统各方面的功能,因此这种打包里面的操作系统功能将不包括整个传统操作系统的功能。
在这种打包发布模式下,用户的运行环境只有虚拟机,而与传统操作系统剥离。应用软件开发商无需针对不
同的操作系统为自己的软件开发多个版本,而只需要支持一种操作系统即可。由于一个应用只为一个操作系
统而写,因此应用软件开发商可以选择一个最能增加应用软件稳定性的操作系统作为平台来打包发布。这样
一个重要的问题就是应用软件开发商如何选择最合适的操作系统。考虑的因素当然包括安全性、稳定性、易
用性、功能性和效率。至于每一个因素所应该占的比重到底是多少,当然是仁者见仁、智者见智,也因软件
开发商的不同而不同。
无论虚拟化或者去虚拟化,无论操作系统与应用软件打包还是不打包,一个不变的因素是扮演魔术师与管理
者角色的这种软件是不可或缺的,不管这个角色是叫做操作系统,还是叫做虚拟机,或者是其他更加令人匪
夷所思的名称。其实,名称叫什么不要紧,关键的问题是学习掌握如何扮演魔术师和管理者。而达到这个目
的途径就是——学习操作系统。
操作系统奇异点
随着人们不断提高对信息安全重视程度,如何构建可靠、可用和安全的操作系统就成为一个十分重要的课
题。而对可靠、可用和安全的追求无疑将令操作系统更复杂,操作系统的规模也将不断增大。从UNIX的
1400行代码到Windows XP的4000万行代码,这完全是一种爆炸式增长。而爆炸式增长的后果就是,操作系
统设计已经变得极为复杂和困难。以致商用操作系统在关键机制的实现上都或多或少地进行了偷工减料,从
而严重影响了操作系统的稳定性。另外,规模的庞大使得没有什么人能够完全理解一个完整的操作系统,而
这种状况同样将限制操作系统的可靠性、可用性和安全性。这迫使我们不得不思考:操作系统能在复杂性和
规模不断增加的情况下保持正确性和可靠性吗?它能在今天的云计算时代取得突破,而达到我们所祈望
的“操作系统奇异点”(OS singularity)吗?
经上写着,不要预测将来。那就让我们拭目以待吧……思考题
1.请列出你曾经用过的所有操作系统。哪个操作系统你觉得最好?为什么?
2.在你用过的操作系统中,你感觉哪个操作系统最好?解释你的答案。
3.计算机从过去单一操作员单一控制终端到现在的个人机,似乎我们转了一个圈。是不是我们人类总是喜欢
反复无常呢?请阐述你对这种否定之否定的观点。
4.虽然我们不赞成对未来进行预测,但你是否对操作系统的未来演变有自己的看法呢?
5.MULTICS的出现在很大程度上是由于IBM的傲慢,你认为人的傲慢在操作系统发展过程中占据什么样的角
色呢?
6.驱动操作系统发展的主要动力有哪些?它们是如何驱动的?
7.很多人都说,没有操作系统的计算机是一堆废铁,无法运转。但在计算机刚诞生的时候,谁也不知道操作
系统这回事儿。那个时候的计算机为什么在没有操作系统的情况下能够运转呢?它们又是如何运转呢?
8.操作系统根据其运行的计算机硬件结构不同而分为主机操作系统、服务器操作系统和个人机操作系统。简
要论述这三种操作系统的关键不同点。
9.MACH所提倡的微内核操作系统因为运行效率低下而没有获得广泛的商业应用,你认为其效率低下的原因
何在?
10.简要论述实时操作系统和分时操作系统的区别。第3章 操作系统基本概念
引子:软件师的尴尬
有一个小幽默也许读者听过,说是三个数学家和三个软件师(即软件工程师或软件专家)在一列火车上相
遇。攀谈中,六个人发现大家都是去参加同一个会议的。然而让软件师们吃惊的是,三个数学家只买了一张
车票,而他们却各买了一张票。
三个软件师于是问数学家:“你们三个人只买一张票,等会儿列车员查票你们怎么办呢?”(这里需要指出的
是,西方的火车站不查票,而是在车上查票。)
三个数学家回答说:“这你们就不懂了吧。你们看好了,学习学习。”
过了不久,果然开始查票。只见三个数学家急急忙忙跑到厕所里面,将门从里面反锁上。查票员过来后敲厕
所的门,问:“查票了,里面有人吗?”里面传来一个声音:“有人,但正在上厕所,无法开门,能否将车票
从门底下递出来检查?”这个时候厕所门下面递出来一张车票。查票员看了没有任何问题,于是就离开了。
三个软件师看完这一幕,十分惊叹。心想,数学家就是比开发软件的人聪明,我们怎么从来没有想到这一招
呢?于是,他们相约回程再同乘一趟车。
过了几天,开完会后,六个人在回程中又聚到了一起。见面后,三个软件师就迫不及待地告诉数学家
们:“我们这次只买了一张票。你们是否也只买了一张票?”
只见数学家们微笑着,不动声色地回答道:“我们这次没有买票。”
软件师们一听,都不敢相信自己的耳朵,接着问道:“那你们这次怎么应付查票呢?”
数学家们丢下一句话:“你们自己想吧。”
软件师们想了半天,实在想不出来有什么办法可以应付查票员。没有办法,只好硬着头皮来问数学家:“我
们想不出来,你们告诉我们吧。”
数学家们仍然微笑着说:“你们的脑袋不够用了吧。看我们再教你们一招。”
过了不久,开始查票了。三个软件师急急忙忙跑到厕所里面,将门从里面反锁上。这时有人敲厕所的门,说:“查票了,里面有人没有?”里面传来一个声音:“有人,但正在上厕所,无法开门,能否将车票从门底
下递出来检查?”这个时候厕所门下面递出来一张车票。
门外的人接了车票,却再也没有递回来……
“差不多”精神
这个幽默对于学软件的人来说,也许不会感到很好笑,可对于学数学的人来说,听后感觉很好笑。开发软件
的人认为数学家的薪水没有他们高,于是编造这么个故事来趁机阿Q一把。
不过静下心仔细想一想,发现数学家的做法还真有点道理。这个道理不是别的,而是因为数学是一门严谨的
学科,一切都以精确为追求(这里是指纯数学,不包括那些不被认为是数学的应用数学)。而软件却没有任
何精确可言,是十足的“差不多”学科。因为软件是一门人造学科,它没有对与错(这里指的是同一功能的不
同实现,而不是说程序不可能出现错误),只有好或坏。我们设计软件的时候,也是觉得差不多就可以了,而没有什么精确的追求。
如果不信,就看看我们是如何分析算法的吧。我们使用所谓的渐进分析,将系数和非决定项都忽略不计,所
谓的“只要数量级对就差不多”。至于软件可靠性、健壮性和成本估算,那就更不用说了,连差不多都不如,而是差很多。
操作系统作为一种软件,自然也是“差不多”就可以了,其中的许多设计都是各种折中的结果,到处体现
着“差不多”精神。读者在学习操作系统时只要留心观察,就会发现很多这些差不多。而要理解这种“差不
多”系统,自然需要抱着一种“差不多”的态度。如果一切吹毛求疵,学习操作系统会非常痛苦,也很难精确
(不好意思,用了一次“精确”)把握操作系统的精髓。
令人欣慰的是,中国人自古就有“差不多”的思维逻辑,因此采纳“差不多”的态度对于中国人是一件很容易的
事情。从这种角度看,学好操作系统是水到渠成的事情。(这里需要强调的是,笔者并不是说计算机学科中
没有任何需要精确的时候,而是说在计算机学科里面体现“差不多”的地方非常多,以致整个学科都带有某种“差不多”的精神)。
前面说过,操作系统是一种软件,它运行在硬件上,又为更高层的应用软件提供服务。因此,对底层硬件的
了解将帮助我们更好地掌握操作系统。下面我们就从计算机硬件开始介绍,探讨一下操作系统的主要概念。3.1 计算机硬件基本知识
从概念上讲,计算机的结构非常简单:首先布置一根总线,然后将各种硬件设备挂在总线上。所有的这些设
备都有一个控制设备,外部设备都由这些控制器与CPU通信。而所有设备之间的通信均需通过总线,如图3-
1所示。图3-1中的粗线条表示总线。
图 3-1 计算机结构概览图
为了提高计算机的效率,人们又设计出了流水线结构,即仿照工业流水装配线,将计算机的功能部件分为多
个梯级,并将计算机的每条指令分拆为同样多个步骤,使每条指令在流水线上流动,到流水线最后一个梯级
时指令执行完毕。流水线上的每个梯级都可以容纳一条指令并同时执行,如图3-2所示。
图 3-2 5个梯级的流水线结构
为了进一步提高计算机的效率,在流水线的基础上,人们又发明了多流水线、超标量计算和超长指令字等多
指令发射机制。这些机制的发明在提升计算机效率(主要是吞吐量)的同时,也极大地增加计算机结构的复
杂度,并对操作系统和编译器提出了更高的要求。
图3-3描述的是一个超标量发射的体系结构。这个结构有两队指令读取和译码单元,以及三个执行单元。通
过一个指令保持缓冲区,就可以实现多路复用(multiplex)和反多路复用(de-multiplex),从而提高系统每
个功能单元的利用率和整个系统的吞吐量。
图 3-3 4个梯级的超标量发射结构
除了指令执行单元外,计算机中的另一个重要部件是指令的存放单元,称为存储架构。存储架构包括了缓
存、主存、磁盘、磁带等。有的情况下还存在多级缓存和外部光盘。图3-4描述的是一个包括寄存器的5级存
储介质构成的存储架构。
从寄存器到磁带,每一级存储媒介的访问延迟和容量均依次增大,而价格却依次降低。寄存器的访问速度最
快,容量最小,但成本最高;磁带的访问速度最慢,容量最大,成本却最低。通过合理搭配,可以形成一个
性价比颇高的存储架构。图 3-4 典型的5级存储结构
磁盘是计算机的主要存储媒介。可以说,没有磁盘,计算机就不能称为计算机,或者说计算机的用处就要大
打折扣。虽然确实存在无磁盘的计算机(即disk-less计算机),但这些计算机都是专用的,并不是给一般用
户用的。磁盘从概念上看非常简单,每张磁盘有多块盘片,盘片两面都可以存储数据。图3-5描述的是典型
的磁盘结构。
图 3-5 典型的磁盘内部结构
中断是计算机里面的一个最为重要的机制,它也是操作系统获得计算机控制权的根本保证。若没有中断,很
难想象操作系统能够完成人们所赋予的任务。中断的基本原理是:设备在完成自己的任务后向CPU发出中
断,CPU判断优先级,然后确定是否响应。如果响应,则执行中断服务程序,并在中断服务程序执行完后继
续执行原来的程序。图3-6简单地描述了中断机制。
中断是一个很复杂的过程,中断处理过程中又可以发生中断,且还可以有所谓的软中断,即软件发出的中
断。透彻理解中断对了解计算机操作系统的运行具有重要意义。因此,对中断机制不甚了解的读者请复习在
计算机组成与体系结构中所学习的中断内容。
图 3-6 磁盘中断的响应流程3.2 抽象
我们已经多次提到过,操作系统提供的是一个抽象。所谓的抽象,就是在根本上存在但现实中不存在的东西
(exist in essence but not in reality)。那么到底怎样理解抽象呢?
抽象来源于具体,但又超越具体。例如,人是具体的动物。但如果将人的具体属性,如肉体和骨架全部剥
离,剩下的就是抽象,即人的灵魂。绘画史上有抽象派,而抽象画所表现的就是现实中不存在的东西,但这
些东西确实又来源于现实,如瓦西里·康定斯基的《海战》(见图3-7)。
图 3-7 康定斯基的《海战》:来源于现实,又高于现实
操作系统提供的抽象自然也来源于现实,就是具体的计算机硬件,如CPU、内存、IO设备等。但又超出这
些现实,给人提供了强于现实的东西,使人和应用软件感觉到更多、更好的硬件存在,而且只存在于操作系
统层面,一般的人才会觉得计算机是可以使用的。
另外,抽象不只是操作系统提供给用户的一个存在,它也存在于操作系统内部。操作系统内部分为不同的功
能块,而不同的功能块之间互相提供的也是抽象。3.3 内核态和用户态
就像世界上的人并不平等一样,并不是所有的程序都是平等的。世界上有的人占有资源多,有的人占有资源
少,有的人来了,别人得让出资源,有的人则专门为别人让出资源。程序也是这样的,有的程序可以访问计
算机的任何资源,有的程序则只能访问少量受限资源。操作系统作为计算机的管理者,自然不能和被管理者
享受一样的待遇。它应该享有更多的方便或权限。为了区分不同的程序的不同权限,人们发明了内核态和用
户态的概念。
那么什么是内核态,什么又是用户态呢?只要想一想现实生活中处于社会核心的人与处于社会边缘的人有什
么区别,就能明白处于核心的人拥有的资源多!因此,内核态就是拥有资源多的状态,或者说访问资源多的
状态,称为特权态。相对来说,用户态就是非特权态,在此种状态下访问的资源将受到限制。如果一个程序
运行在特权态,则该程序就可以访问计算机的任何资源,即它的资源访问不受限制。如果一个程序运行在用
户态,则其资源需求将受到各种限制。
例如,如果要访问操作系统的内核数据结构,如进程表,则需要在特权态下才能办到。如果要访问用户程序
里的数据,则在用户态就可以了。
由于内核态的程序可以访问计算机的所有资源,因此这种程序的可靠性和安全性就显得十分重要。试想如果
一个不可靠的程序在内核态下修改了操作系统的各种内核数据结构,结果会怎样呢?整个系统有可能崩溃。
运行于用户态的程序就比较简单,如果其可靠性和安全性出了问题,其造成的损失只不过是让用户程序崩
溃,而操作系统将继续运行。
很显然,内核态和用户态各有优势:运行在内核态的程序可以访问的资源多,但可靠性、安全性要求高,维
护管理都较复杂;用户态程序程序访问的资源有限,但可靠性、安全性要求低,自然编写维护起来比较简
单。一个程序到底应该运行在内核态还是用户态则取决于其对资源和效率的需求。
一般来说,如果一个程序能够运行于用户态,就应该让它运行在用户态。只在迫不得已的情况下,才让程序
运行于内核态。凡是牵扯到计算机本体根本运行的事情都应该在内核态下执行,只与用户数据和应用相关的
东西则放在用户态执行。另外,对时序要求特别高的操作,也应该在内核态完成。
那么什么样的功能应该在内核态下实现呢?首先,CPU的管理和内存管理都应该在内核态实现。这些功能可
不可以在用户态下实现呢?当然能,但是不太安全。从保障计算机安全的角度来说,CPU和内存的管理必须
在内核态实现。
诊断与测试程序也需要在内核态下实现。因为诊断和测试需要访问计算机的所有资源,否则怎么判断计算机
是否正常呢?就像中医治病,必须把脉触摸病人。你不让中医触摸,他怎么能看病呢(当然,很多人认为中
医是伪科学,根本治不了病,本书对此问题不做讨论)?输入输出管理也一样,因为要访问各种设备和底层
数据结构,所以也必须在内核态实现。
对于文件系统来说,则可以一部分放在用户态,一部分放在内核态。文件系统本身的管理,即文件系统的宏
数据部分的管理必须放在内核态,否则任何人都可能破坏文件系统的结构;用户数据的管理则可以放在用户
态。编译器、网络管理的部分功能、编辑器、用户程序等,自然都可以放在用户态下执行。图3-8描述的是
Windows操作系统的内核态与用户态的界线。
图 3-8 Windows操作系统的内核态与用户态的界线
3.3.1 态势的识别那么计算机是如何知道现在正在运转的程序是内核态程序呢?而正确做出内核态或用户态的判断对系统的正
确运行至关重要。显然做出这种判断需要某种标志。这个标志就是处理器的一个状态位。这个状态位是CPU
状态字里面的一个字位。也就是说,所谓的用户态、内核态实际上是处理器的一种状态,而不是程序的状
态。我们通过设置该状态字,可以将CPU设置为内核态、用户态或者其他的子态(有的CPU有更多种子
态)。一个程序运行时,CPU是什么态,这个程序就运行在什么态。3.3.2 内核态与用户态的实现
前面说过,内核态是特权态,而用户态是普通态。特权态下运行的程序可以访问任何资源,而用户态下的访
问则受到限制。那么这种限制是如何实现的呢?
显然,要限制一个程序对资源的访问,需要对程序执行的每一条指令进行检查才能完成。而这种检查就是地
址翻译。程序发出的每一条指令都要经过这个地址翻译过程。而通过对翻译的控制,就可以限制程序对资源
的访问。关于地址翻译的内容本书将在第12章详细阐述。
为了赋予内核态程序访问所有资源的权限,当系统处于内核态时,内核程序可以绕过内存地址翻译而直接执
行特权指令,如停机指令。这种绕过翻译的做法突破了系统对资源的控制。
本书在介绍完进程和内存后,将再次讨论内核态与用户态的议题。3.4 操作系统结构
操作系统的结构也和操作系统历史类似,经历了好几个阶段。在操作系统刚刚出现时,人们还没有意识到操
作系统的存在,也没有将那些库函数称为操作系统。那个时候,人们想到什么功能,就把那个功能加进来,并没有对所有的功能进行统筹兼顾的计划。自然,那个时候的操作系统就是杂乱的、无结构的。
而随着操作系统的演化,人们对操作系统的认识逐步加深,操作系统慢慢多了一些结构。各种功能归为不同
的功能块,每个功能块相对独立,又经过固定的界面互相联系。任意一个功能块都可以调用另一个功能块的
服务。整个操作系统本身是一个巨大的单一体(monolithical system),运行在内核态下,为用户提供服
务,如图3-9所示。
图 3-9 单一体的操作系统结构
后来人们发现单一体的操作系统结构有很多缺点:功能块之间的关系复杂,修改任意功能块导致其他所有功
能块都需要修改,从而导致操作系统设计开发困难;这种没有层次关系的网状联系容易造成循环调用,形成
死锁,从而导致操作系统可靠性降低。这时候,人们想到了人类社会中的层次关系,何不将人类熟悉的层次
关系搬到操作系统设计里,定义操作系统的层次关系呢?将操作系统的功能分成不同层次,低层次的功能为
紧邻其上一个层次的功能提供服务,而高层次的功能又为更高一个层次的功能提供服务。就像人类团体中的
结构:村长→镇长→县长→市长……如图3-10所示。
图 3-10 层次化的操作系统结构
从图3-9和图3-10可以看出,操作系统的所有功能都在内核态下运行。而这带来了几个问题。首先,操作系
统的所有服务都需要进入内核态才能使用,而从用户态转换为内核态是有时间成本的,这样就造成操作系统
效率低下。在操作系统还比较简单时这个问题并不突出,但随着操作系统功能和复杂性的增加,这种问题就
十分明显了。其次,前面说过,在内核态运行的程序可以访问所有资源,因此其安全性和可靠性要求十分高。在操作系统
规模很小时,将其设计得可靠和安全并不困难。而且,在操作系统历史的早期也没有那么多安全问题,自然
安全上的考虑就不用太多。但随着操作系统越来越大,破坏者的水平越来越高,操作系统的可靠性和安全性
就变得很难达到。只要想一想,1400行代码的操作系统和4000万行代码的操作系统有什么区别就知道了。
因此,人们又想出了一个办法,就是微内核结构,即只将操作系统核心中的核心放在内核态运行,其他功能
都移到用户态运行。这样就同时提高了效率和安全性(见图3-11)。
图 3-11 微内核的操作系统结构
各种操作系统结构各有优缺点,但当前的趋势是第三种模式,即微内核的操作系统结构。至于这个微内核到
底有多“微小”,则是仁者见仁、智者见智。例如,美国卡内基梅隆大学开发的MACH操作系统的内核非常
小,而微软公司的Windows XP的内核就大多了。3.5 进程、内存和文件
进程是操作系统里面的核心概念。它指的是一个运动中的程序。从名字上看,进程表示的就是进展中的程
序。一个程序一旦在计算机里运行起来,它就成为一个进程。操作系统对进程的管理通过进程表来实现。进
程表里存放的是关于进程的一切信息。在任何时候,进程所占有的全部资源,包括分配给该进程的内存、内
核数据结构和软资源形成一个进程核(core)。核快照(core image)代表的是进程在某一特定时刻的状
态。
如果在Linux或UNIX操作系统下编写程序,在出现分段错误(segmentation fault)时,操作系统会自动进行
核倒出(core dump)。“核倒出”把所有计算机的状态保存在一个文件中,通过阅读这个文件的内容可以得
知溢出时的进程状况,从而帮助调试程序。
进程与进程之间可以通信、同步、竞争,并在一定情况下可能形成死锁。这些概念都将在第4章进行详细阐
述。
内存是操作系统里面的另一个核心概念。它是进程的存放场所。如何对内存进行管理,使得数据的读写具有
高效率、高安全、高空间利用率和位置透明的特性是内存管理所要达到的目的。
文件是操作系统提供的外部存储设备的抽象,它是程序和数据的最终存放地点。如何让用户的数据存放变得
容易、方便、可靠和安全是文件系统要解决的问题。3.6 系统调用
前面说过,操作系统是一个系统程序,即为别的程序提供服务的程序。那么操作系统的服务是通过什么方式
提供的呢?答案是系统调用(system call)。系统调用就是操作系统提供的应用程序界面(Application
Programming Interface, API)。用户程序通过调用这些API获得操作系统的服务。例如,如果用户程序需要进
行读磁盘操作,在C程序代码里将使用下面的语句:
result=read(fd, buffer, nbytes);
这个read函数是C语言提供的库函数,而这个库函数本身则是调用的操作系统的read系统调用。注意这里有
两个read,一个是read库函数,由程序语言提供;另一个是read系统调用,由操作系统提供。编译器在看到
上述语句后将read库函数扩展为read系统调用。在真正执行时,操作系统将完成上述文件的读操作。
系统调用按照功能可以划分为六大类:
●进程控制类。
●文件管理类。
●设备管理类。
●内存管理类。
●信息维护类。
●通信类。
系统调用一般不在操作系统原理的课程中论述,而是在操作系统编程或系统编程的课程中论述。这里我们简
单说一下系统调用的过程。系统调用分为三个阶段,分别是:
●参数准备阶段。
●系统调用识别阶段。
●系统调用执行阶段。
在参数准备阶段,需要使用系统服务的程序将系统调用所需要的参数,如上述例子中的fd、buffer、nbytes,压入栈中。然后调用read库函数。read库函数将read系统调用的代码放在一个约定好的寄存器里,通过陷入
(trap,一种中断方式)将控制交给操作系统。由此进入第二个阶段。操作系统获得控制权后,将系统调用
代码从寄存器里取出,与操作系统维护的一张系统调用表进行比较,获得read系统调用的程序体所在的内存
地址。之后跳到该地址,进入到第三阶段,执行系统调用函数。系统调用执行完毕后返回到用户程序(见图
3-12)。图 3-12 read系统调用的过程
系统调用中的参数传递
从图3-12可以看出,read系统调用的参数被压入到栈中,即参数传递是通过栈来进行。但这并不是唯一的参
数传递办法。事实上,这还不是效率最高的传递方法。效率最高的方法是将参数存放在指定的寄存器里面。
由于寄存器的访问速度高于栈,因此这种参数传递将可以提升系统调用执行的效率。例如,在x64体系结构
下,最前面的8个参数由寄存器传递。只有超过8个参数时,后面的参数才通过栈来传递。3.7 壳
3.4节说明了操作系统是如何给用户程序提供服务的。用户程序通过调用操作系统提供的系统调用API来获得
操作系统的各种服务。但使用API需要编程。对于不编程序的用户来说,或对于需要与操作系统进行交互的
用户来说,又怎么使用操作系统的服务呢?
为了向这些不编程的用户提供服务,操作系统提供了一个壳(shell)来与用户交互。每个操作系统都提供某
种壳,以便与用户进行交互。这个壳是覆盖在操作系统服务上面的一个用户界面,既可以是图形界面,也可
以是文本界面。用户在这个界面上输入命令,操作系统则执行这些命令。当然,用户输入的命令不是直接的
操作系统服务,而是所谓的utilities。utilities的功用相当于C语言中的库函数。因为用户不能直接调用系统调
用(至于为什么不能留给读者思考),C语言提供了库函数来解决这个问题。
同理,在壳上用户也不能直接使用操作系统的服务,而是通过utilities来获得操作系统服务。UNIX和Linux的
壳都是文本形式,而Windows的壳是图形界面的。在UNIX和Linux里,要启动一个壳只需要运行shell即可。
在Windows里面,要启动壳需要执行explore.exe。在Linux和UNIX中可以同时启动多个壳,而在Windows下
只能启动一个壳。2006年,微软公司推出了Powershell,从此改变了在Windows下只能启用一个壳的限制。
Powershell是一个文本命令壳,可以运行在Windows XP SP2、Windows Server 2003、Windows Vista和
Windows Server 2008上。Powershell提供了一种类似于UNIX和Linux上utilities的东西,称作cmdlets。用户通
过键入cmdlets里面不同的命令而指挥计算机进行各种操作。
一个壳的具体功能包括如下几项:
●显示提示符,如UNIX下的提示符通常为-和%。
●接受用户命令并执行。
●实现输入输出间接(或间接输入输出)。
●启动后台进程。
●进行工作控制。
●提供伪终端服务。
例如:可以在UNIX shell上执行下述命令:
键入:$date
显示:$September 16,2008
还可以进行输出间接(或间接输出):
键入:$date>file
显示:$
上述命令行里面的“>”符号是间接符号,将输出从显示屏转移到了文件file。如果打开文件file,里面的内容
将是September 16,2008。
还可以同时进行输入和输出间接(或间接输入输出):
$sort
上述命令将file1里面的内容进行排序,然后将排序后的结果存放在文件file2里。
还可以将输出间接发送到打印机:
$cat file1 file2 file3>devlp1
上述命令将file1、file2、file3里面的内容进行连接,然后将结果发送到打印机lp1并打印。
可以启动后台程序:
$make all>log&上述命令启动一个编译后台程序,将编译的结果输出到文件log里。
那么壳是怎么实现的呢?下面是一个最为简单的壳(UNIX shell的伪代码,并不能真正运行):
while(true){
type_prompt;显示命令提示符
read_command(command, parameters)从用户获得命令
if(fork==0){fork一个子进程
execve(command, parameters,0);子进程代码,执行用户命令
}
else{父进程代码段
waitpid(-1,&status,0);等待子进程结束
}
}
这个壳一旦启动,就循环往复直到无穷。它所做的事情很简单:
1)显示命令提示符。
2)等待用户输入命令。
3)使用fork创建一个子进程。
4)使用execve在创建的子进程里执行用户输入的命令。
5)重复步骤1)~4)。
上述程序段里的fork和execve均为UNIX操作系统提供的系统调用。fork的功能是创建一个子进程,并将自己
的一切数据复制到子进程里,也就是说,fork完成的实际上是自我复制。execve的功能是用另外一个程序的
内容覆盖自己,即执行新的程序。
这里值得一提的是,在上述程序代码里,fork命令有两次返回:一次返回值为0,表明是子进程(创建的新
进程),对应if-else复合语句中的if部分;另一次返回值不是0,表明是父进程,对应if-else复合语句中的else
部分,而这个返回值就是子进程的进程ID。也就是说,复合语句if-else的if和else部分在fork完成后都将执
行。这听上去奇怪吗?
如果奇怪,那是因为你看到的是一个程序。我们知道,在一个程序里,if-else语句的if和else两个部分只能有
一个部分执行,而不能两个部分同时执行。我们还知道,一个函数是无法返回两次的。因为只要写了
return,后面的语句就不能再执行了。也就是说,return后面无法再出现return了,即一个函数不能返回两
次。那么fork命令为什么能返回两次呢?
这是因为fork的特殊功能使然。fork的功效是创建一个和自己完全一样的进程。在fork系统调用完成后,我们
面对的是两个进程,而不再是一个进程。这两个进程的程序代码完全一样,就是我们上面给出的代码。在其
中一个进程中,执行的是if部分;在另一个进程中,执行的是else部分。因此,从每一个进程内部来看,复
合语句if-else的语义并没有遭到破坏。
而且,既然在fork后有了两个副本,那么每个副本里都有同样的fork调用语句。从另一个角度讲,有两个程
序调用了fork。这两次调用都需要返回。从内存结构看,这两个程序副本或者进程都有自己的调用栈,并都
有调用返回的位置。对于每一个进程来说,它调用了一次fork,获得了一次返回。因此,从每个进程内部
看,也遵循了函数返回一次的语义。
那么系统中的两个一模一样的进程如何区分呢?这个比较简单,给每个进程一个不同的返回值即可。返回给
父进程的是子进程的进程ID,对应else部分;返回给子进程的是0,对应if部分。
本章论述了操作系统的基本概念。这些概念为下一步的进程、内存、文件和输入输出等章节的学习打下了基
础。在这些概念中,最为关键的是内核态和用户态的定义及其关系。当然,抽象是操作系统的根本,而系统
调用和操作系统结构也非常重要。思考题
1.操作系统提供的用户界面有几种?分别是什么?
2.举出人类社会中采用的几个抽象示例,并与操作系统提供的抽象进行对比。
3.有人认为,内核态程序可以访问任何资源的权限对系统安全造成严重威胁,你怎么看?
4.处理器的状态设置需要在何种态势下完成?为什么?
5.处理器从用户态转为内核态时面临的关键问题是什么?如何解决?
6.下述操作是否可以在用户态下执行?
a)保护中断现场。
b)因系统调用陷入内核。
c)启动外部设备。
d)外设与内存经DMA进行数据交换。
e)缺页中断。
7.论述系统调用和壳之间的关系。
8.操作系统采用层次结构的优点是什么?层次结构有什么缺点?
9.fork是如何实现一次调用两次返回的?它有必要吗?为什么?
10.请调研当前业界通用系统里面缓存、主存、磁盘、磁带的平均容量。11.挑战题:内核态的特权是如何实
现的?第二篇 进程原理篇
恍兮惚兮,其中有像;惚兮恍兮,其中有物
有了基础原理篇的铺垫,我们就可以进入操作系统核心功能部件了。
顾名思义,计算机是用来进行计算的,或者说计算机的基本功能是计算功能。而进行计算的关键部件是计算
机的芯片,即CPU。CPU能够按照一定的顺序进行正确计算是在一个指挥者的控制之下完成的。这个指挥者
就是操作系统。操作系统对CPU进行管理的重要手段就是进程模型,或者说进程是操作系统这个魔术师施法
的道具。
进程是操作系统演化过程中的一个里程碑,由于进程的出现,人类希望的并发从理想变为了现实。从根本上
说,进程出现的动机是人类渴望的并发。进程的出现也让操作系统的复杂性大为增加:由于需要对进程进行
分离存储而导致出现内存管理;由于需要让不同进程有条不紊地往前推进而导致进程调度的出现。显然,理
解进程对理解操作系统十分重要,对其进行管理也就理所当然地成为操作系统的一个关键职责。
本篇包括第4~6章的内容。第4章阐述的内容包括进程出现的逻辑必然性、多道编程的效率、进程的创建和
消亡、进程的状态及其转换、进程与地址空间、进程管理和进程模型的缺陷。第5章讲解的内容包括调度的
目标、先来先服务、时间片轮转、短任务优先、优先级调度、混合调度、实时调度等算法,并对优先级倒挂
和线程的不确定性进行讨论。第6章包括为什么要通信、管道、记名管道、套接字、信号、信号量、共享内
存、消息队列等。
进程从根本上说是操作系统对CPU进行的抽象和装扮
本篇最重要的内容是并发。因为要并发,所以我们发明了进程。第4章 进程
引子:牛顿的困惑
在艾德蒙德·哈雷(Edmond Halley)的耐心劝说和敦促下,牛顿(Issac Newton)(见图4-1)撰写了其传世
名作《自然哲学的数学原理》(Philosophiae Naturalis Principia Mathematica,一部包含牛顿经典力学和万
有引力定律的物理学著作)。在完成此书后,一种困惑始终挥之不去。牛顿写完此书后的总览后对他的朋友
哈雷感叹道:“一切物体的运动规律,天上的、地上的,我已经全部、完美地阐述清楚了。但一个一直困惑
我的问题是:这些规律是从何而来的?或者说这些太空中的天体、地上的物体为什么会遵守这些规律呢?它
们如果不遵守这些规律,难道我们还能把它们怎么样不成?”
如果这些规律是随着时间与整个宇宙一起进化或演变的,则在进化到一半的时候,即在这些规律既是规律,又不是规律,或者说还是“半规律”时,宇宙是如何得以存在的呢?我们知道天体的运行轨道只要偏离一点,其存在就有可能大成问题,如果很多天体都随机运动,则后果将不堪设想。因此,按照“半规律”存在的宇宙
是不可想象的。
剩下的唯一推论就是,这些规律在宇宙出现的一刹那就完美地存在了。或者更为直白地说,这些规律在宇宙
存在之前就已经存在了。而这与《约翰福音》里的In the beginning was the word(太初有道)不谋而合。这
里的word是希腊语原文logos的英文翻译。而logos就是逻辑,就是规律。这句话的意思是在还没有宇宙的时
候,规律就已经存在了。
而由于规律本身不是物质,其存在自然是无中生有了。至于是谁或者什么导致这些规律的存在,那就留给读
者自己去遐思了……
本章讨论的进程也是无中生有。这点与宇宙的运行规律有一些相似。不过与宇宙规律不同的是,我们知道是
谁导致了计算机中进程的出现:人!
当人们面临困境时通常的做法就是:发明新的概念、新的术语或新的机制来解脱困境。
图 4-1 位于剑桥大学三一学院门厅里的牛顿雕像4.1 进程概论
进程管理、内存管理和文件管理是操作系统的三大核心功能。那么什么是进程呢?顾名思义,进程就是进展
中的程序,或者说进程是执行中的程序。就是说,一个程序加载到内存后就变为进程。即:
进程=程序+执行
进程在Multics操作系统出现前叫做工作(job)。工作是IBM用于多道批处理程序设计中的概念。由于历史
的原因,Multics操作系统的研发人员不愿意承用IBM发明的术语,而将工作改为了进程(process)。那么进
程出现的动机是什么呢?
本书在第2章提到,单一操作员单一控制终端、批处理均存在效率低下的问题,即CPU使用率不高。为了提
高CPU利用率,人们想起将多个程序同时加载到计算机里,并发执行。这些同时存在于计算机内存的程序就
称为进程。进程让每个用户感觉到自己独占CPU。因此,进程就是为了在CPU上实现多道编程而出现的概
念,如图4-2所示。
图 4-2 进程让每个用户感觉到自己独占CPU4.2 进程模型
那么进程到底是什么呢?什么是进展中的程序呢?从物理内存的分配来看,每个进程占用一片内存空间,从
这点上说,进程就是内存的某片空间。由于在任意时刻,CPU只能执行一条指令,因此任意时刻在CPU上执
行的进程只有一个,而到底执行哪条指令由物理程序计数器指定。也就是说,在物理层面上,所有进程共用
一个程序计数器。
而从逻辑层面上来看,每个进程可以执行,也可以暂时挂起让别的进程执行,之后又可以接着执行。这样,进程就需要某种办法记住每次挂起时自己所处的执行位置,这样才能在下次接着执行时从正确的地点开始。
因此,从这个角度看,每个进程有着自己的计数器,记录其下一条指令所在的位置。从逻辑上说,程序计数
器可以有很多个。
而从时间上看,每个进程都必须往前推进。在运行一定的时间后,进程都应该完成了一定的工作量,即每次
进程返回,它都处在上次返回点之后。这就像古希腊哲学家赫拉克里特说过的:“一个人不能两次踏入同一
条河流。”进程的这3种概念可以由图4-3表示。
图 4-3 进程模型的3个视角
这里需要注意的是,进程不一定必须终结。事实上,许多系统进程(用来为别的进程提供系统服务的进程)
是不会终结的,除非强制终止或计算机关机。
进程模型的实现
对于操作系统来说,进程是其提供的一种抽象,目的是通过并发来提高系统利用率,同时还能缩短系统响应
时间。这种抽象听上去很不错。但这种抽象是如何实现的呢?或者说,操作系统如何实现进程呢?
首先,任何抽象都需要有一个物理基础。对于进程来说,其物理基础就是程序。程序运行在计算机上,而在
计算机上运行首先需要解决的问题是进程的存储:给进程分配合适的内存,让其有一个安身之处。由于多个
进程可能同时并存,因此进程的存储需要考虑如何让多个进程共享同一个物理内存而不发生冲突。操作系统
解决这个问题的手段是内存管理。
此外,进程运行实际上是指进程在CPU上执行。那么如何将CPU在多个进程之间进行交接或切换,这就是进
程实现需要解决的另一个问题。操作系统解决这个问题的手段就是进程调度:决定在什么时候让什么进程使
用CPU。这个议题将在本书第5章予以讨论。4.3 多道编程的好处
人们发明进程是为了支持多道编程,而进行多道编程的目的则是提高计算机CPU的效率,或者说系统的吞吐
量。例如,如果一个进程有20%的时间使用CPU进行计算,另外80%的时间用来进行IO,则如果使用单道编
程,CPU的利用率只有20%。但如果同时运行两个这样的进程,即进行所谓的2道编程,则CPU利用率将提
高到36%(CPU只在两个进程同时进行IO时才处于闲置状态,因此CPU的利用率为1-0.8×0.8=36%)。这里
忽略了进程切换所需要的系统消耗。
同理,如果同时运行3个这样的进程,则CPU利用率将进一步提高到48.8%。4个进程的CPU利用率将为
59%,5个进程的CPU利用率为67.2%,6个进程的CPU利用率为73.8%,7个进程的CPU利用率为80%。这
样,随着进程数量的增加,也就是随着多道编程的度的增加,CPU利用率将逐步提升,但提升的幅度则逐步
降低,直到某个临界点时为止。这个临界点就是多道编程的极限。超过这个极限,多道编程的好处将逐步消
失,甚至呈下降趋势。对于这个系统来说,多道编程的度达到12以后,CPU利用率已经达到94%,之后CPU
利用率的提升空间就很小了,而因为进程切换所带来的系统消耗则变得非常明显。多道编程的度数与CPU效
率的关系如图4-4所示。
图 4-4 多道编程度数和CPU利用率的关系(IO时间为80%)
这里需要注意的是,图4-4描述的是一种非常简单的模型:所有的进程都进行同样的IO工作量(80%),且
进程切换时间忽略不计。如果情况不是这样,例如不同的进程进行IO的工作量各不相同,且进程切换时间
也需要考虑,则CPU利用率的图线就不是这么简单了。但图4-4所描述的趋势变化仍然成立:随着度的增
加,CPU利用率增加,直到一个临界点。
响应时间改善
除了提高CPU利用率外,多道编程更大的好处是改善系统响应时间,即用户等待时间。毕竟,对于大多数用
户来说,关心的是计算机的响应速度,至于CPU利用率到底有多高,除了系统管理员或者某些有偏执狂的人
外,一般人是不会在意的。
下面我们通过一个多道编程的具体例子来展示多道编程对系统响应时间的改善。假定我们有4个程序,每个
程序花费80%的时间进行IO,20%的时间使用CPU(这种假设非常符合算法中的80-20规律)。每个程序的
启动时间和其需要使用CPU进行计算的分钟数如表4-1所示。
下面我们来看看该计算机里面各个程序的执行情况(所有计算均为大约情况,不是精确情况)。从0点0分开始到0点10分,程序1开始运行。由于系统里只有1个程序,因此属于单道编程状态。单道编程时
CPU的利用率为20%,因此第1个程序在该10分钟里总共使用了CPU达2分钟(其他8分钟都用来进行IO
了)。
从0点10分到0点20分,程序2开始运行,此时程序1尚未结束,系统里将有两个程序,因此属于2道编程。我
们前面计算过,2道编程时CPU利用率为36%,因此在这10分钟时间内,CPU使用了3.6分钟。假定这两个程
序完全平等,那么每个程序使用CPU的时间为1.8分钟。至此,程序1总共运行了2+1.8=3.8分钟CPU时间,程
序2运行了1.8分钟CPU时间。
从0点20分开始到0点30分,程序3开始运行,而程序1和2皆未结束,系统里有3个程序,因此属于3道编程状
态。3道编程时CPU的利用率为48.8%,因此在这10分钟时间内,CPU使用了大约4.8分钟(其他5.2分钟都用
来进行IO了)。同样,假定所有程序完全平等,那么每个程序使用CPU的时间为1.6分钟。至此,程序1总共
运行了3.8+1.6=5.4分钟CPU时间,程序2运行了1.8+1.6=3.4分钟CPU时间,程序3运行了1.6分钟。此时,程序
1离结束还需要2.6分钟的CPU时间,程序2离结束还需0.6分钟的CPU时间,程序3离结束所需要的CPU时间最
短,仅为0.4分钟。
从0点30分开始,程序4开始运行,此时程序1、2、3皆未结束,系统里同时有4个程序,因此属于4道编程。
我们前面计算过,4道编程时CPU利用率为59%。而如果程序3想再运行0.4分钟CPU时间,则整个系统需运行
时间为约2.7分钟(2.7分钟时间内CPU共使用1.6分钟,平均每个程序使用的CPU时间为0.4分钟)。因此,在
0点32.7分时,程序3执行完毕,系统中还剩下程序1、2、4,系统变成3道编程。
此时,程序1总共运行了5.4+0.4=5.8分钟CPU时间,程序2总共运行了3.4+0.4=3.8分钟CPU时间,而程序4则
总共运行了0.4分钟。此时,程序2离结束所需的CPU时间最短,为0.2分钟。那么系统需要运行多长时间才能
使程序2获得0.2分钟的CPU时间呢?答案是1.25分钟。因为3道编程的CPU利用率大约为48%,而1.25分钟内
CPU的使用时间是0.6分钟。3个程序平分,每个程序运行了0.2分钟时间。因此,1.25分钟后,也就是在0点
33.95分,程序2结束运行,系统里只剩下程序1和程序4两个程序。
此时,程序1已经使用了5.8+0.2=6分钟CPU时间,程序4已经使用了0.4+0.2=0.6分钟CPU时间。程序4离结束
所需的CPU时间最短,为0.4分钟。而在约2.2分钟后,即0点41.15分,程序4结束运行,剩下程序1。此时程
序1已经运行了6+0.4=6.4分钟,还需用运行8-6.4=1.6分钟。在单道编程的情况下,该程序则在8分钟后,即0
点49.15分结束运行。读者可自行绘出一张各程序的开始和终止时刻图。
在多道编程环境下,4个程序和整个系统的响应时间为:
而在单道编程环境下,4个程序和整个系统的响应时间为:
由上述两个表格的数据可以看出,多道编程比起单道编程,系统平均响应时间缩短了约21分钟,响应时间改
善程度约47%,这是一个巨大的改善。
当然了,多道编程带来的好处到底有多少与每个程序的性质、多道编程的度数、进程切换消耗等均有关系。
但一般来说,只要度数适当,多道编程总是利大于弊。4.4 进程的产生与消亡
什么事件可以造成进程的产生和消亡呢?当然有很多这样的事件。对于进程产生来说,主要的事件有:
●系统初始化(神创造人)。
●执行进程创立程序(人生子)。
●用户请求创立新进程(试管婴儿)。
在一个系统初始化时,将有许多进程产生。产生的这些进程是系统正常运行必不可少的。这些进程的存在使
得新的进程和用户程序的执行成为可能。例如:在系统初始化后,Windows操作系统将自动产生诸如对话管
理(SMSS)、登录管理(WINLOGON)、安全管理(LSASS)、Windows子系统(CSRSS)、Windows壳
(explore)等系统进程。
在系统初始化后,系统就等待用户输入命令。如果这个用户启动一个程序,如双击一个可执行文件,那么系
统将为这个可执行文件创建一个进程。除此之外,用户也可以在程序里面通过系统调用如fork或者
CreateProcess直接生成新的进程。
造成进程消亡的事件则可以分为四种情况:
●寿终:进程运行完成而退出。
●自杀:进程因错误而自行退出。
●他杀:进程被其他进程所终止。
●处决:进程因异常而被强行终结。
前两种情况均为自愿退出,后两种情况均为非自愿退出。在程序设计时我们追求的是前面两种退出,也算是
我们在虚拟世界里面追求人权(进程权)的努力吧。第3种情况通常是一个父进程发出命令终止一个子进
程。当然,一个用户也可以“杀死”自己的进程,但不能“杀死”别人的进程。但一个超级用户(具有系统管理
员权限)则可以“杀死”任何进程。第4种情况在一个进程进行某种非法操作,如访问出界或者除以0后发生,而这种非法操作将被操作系统捕捉。操作系统捕捉到这种异常后将终结造成异常的进程。4.5 进程的层次结构
我们说过,一个进程在执行过程中可以通过系统调用创建新的进程。这个新创建的进程就称为子进程,而创
建子进程的进程则称为父进程。子进程又可以再创建子进程,这样子子孙孙创建下去就形成了所谓的进程
树。UNIX称这个进程树里面的所有进程为一个进程组,进程组里面的进程分布在不同的层次上,从而形成
一个层次架构。
Windows没有进程组的概念,而是所有进程均地位平等。4.6 进程的状态
我们前面说过,进程可以在CPU上执行,也可以处于挂起状态。显然,一个进程至少有这么两种状态。那么
进程还有别的状态吗?
如果进程在CPU上执行,自然就是执行状态。而如果是挂起状态呢?那就得看是什么原因挂起的。因为操作
系统在进行进程调度时要从挂起的进程中选择一个来执行,所以清楚一个进程挂起的原因对调度的有效推进
十分重要。
那么进程挂起有哪些原因呢?首先是一个进程在运行过程中执行了某种阻塞操作,如读写磁盘。由于阻塞操
作需要等待结果后才能继续执行,因此操作系统将把这个进程挂起,让其他进程运转。另外一种情况是一个
进程执行的时间太长了,为了公平,操作系统将其挂起,让其他进程也有机会执行。
这两种挂起的原因十分不同:第一种挂起是进程自身的原因。这个时候,即使把CPU控制权交给它,它也无
法运行。第二种挂起是操作系统的原因。进程自己并无问题。只要把CPU交给进程,它就可以立即运行。这
样,如果将挂起进程分为这样两类,操作系统在进程调度时就只需要查看第二类进程,而无须浪费时间查看
第一类进程。
因此,将进程分为3种状态:执行、阻塞和就绪,如图4-5所示。
在3种状态之间可以进行各种转换。如果每个状态都可以转换为另外一种状态,则一共有6种转换:
图 4-5 进程的3个典型状态
●执行→就绪
●执行→阻塞
●阻塞→就绪
●就绪→执行
●阻塞→执行
●就绪→阻塞
问题是,上面的转换并不是都可以发生。一个进程在执行时,因为运行时间太长,操作系统可以将其挂起,转换为就绪状态,因此第1种转换是可以的。在进程执行过程中如果执行了某种阻塞操作,则进入阻塞状
态,因此第2种转换也是可以的。一个阻塞的进程在其等待的资源到达后,就可以随时执行,进入就绪状
态,因此第3种转换也是可以的。最后,就绪进程由操作系统调度到CPU上就进入执行状态,因此第4种转换
也是可以的。
但是第5、第6两种转换是不可以的。我们前面讲过,阻塞进程即使被给予CPU,也无法执行,因此操作系统
在调度时并不会在阻塞队列里挑选。因此,阻塞状态无法转换为执行状态。对于处于就绪状态的进程来说,因为它并没有执行,自然无法进入阻塞状态。这就像一个人停滞不前,自然就不会有任何人成为其障碍。因
此,就绪状态无法转换为阻塞状态。
这里需要注意的是,第5、第6两种转换虽然都不存在,但其原因不同。第5种转换不可以是因为我们不让它
发生。如果我们乐意,完全可以让操作系统在阻塞队列里挑选一个进程予以执行,只不过这个进程在执行第
1条指令时就会又发生阻塞(因为其等待的数据尚不可用或者发生异常)。因此,从理论上说,阻塞到执行
是可以的,只不过这种状态转换没有任何实际价值而被操作系统禁止。而第6种状态转换则在理论上是不可
以的。一个进程只能在执行时才可能阻塞,没有执行的进程无法直接转换到阻塞状态。这里阐述的进程的3种典型状态并不是唯一的分类方式。事实上,许多商业操作系统的进程状态不止3个,例
如,Windows的进程有7个状态,Solaris的进程则有6个状态。但不管3个、6个、7个还是几个,其目的都是
便于操作系统管理进程。只要细分对管理有利,我们就细分。否则就维持3个状态。4.7 进程与地址空间
进程空间也称为地址空间。简单来说,地址空间就是进程要用的所有资源。于是所有资源就构成了状态的划
分。由于不可能有两个进程状态完全一样,因此每个进程对应计算机的一种状态,而计算机状态就是所有存
储单元的内容。
地址空间的特点就是被动,自己不能做什么,只提供支持。打个比方。看过演出吗?如话剧、芭蕾、歌剧
等。京剧总看过吧?有个舞台,那些道具和舞台就是地址空间。这些空间本身不能发生任何动作。做动作的
只能是演员。而那些演员就是我们将要讲述的线程。跳上来一个演员就是一个线程,如图4-6所示。
图 4-6 音乐剧《剧院魅影》:舞台布景及设施是地址空间,而舞台上的男女演员是线程
进程与地址空间研究的主要内容是如何让多个进程空间共享一个物理内存。具体来说,就是高效、安全地让
所有进程共享这片物理内存。4.8 进程管理
那么谁管理进程的资源?是操作系统。本书前面说过,Operating的意思就是掌控一切。那么如何掌控呢?操
作系统要掌控一切状态,就必须拥有某些手段或资源。那需要什么手段或资源呢?如果让你监视一群人,要
你掌握他们的一切情况,你第一件要做的事是什么?装监视器?不是!而是要知道这群人到底是哪些人!即
你需要知道并维持关于这群人的各种信息!
4.8.1 进程管理所需要的手段
4.4 节讲到了进程的产生和消亡,但这到底是什么意思呢?产生一个进程对于操作系统来说意味着什么
呢?进程消亡又对操作系统有何影响呢?要回答这个问题只需要看一下一个人的出生对一个社会来说意味着
什么就可以了。在一个人出生后,医院需要在几天内为其建立记录,该记录包括诸如姓名、性别、体重、身
高、父母为何人、在何时何地出生、健康状态等信息,然后该记录用来登记户口、办理身份证等。在完成这
些手续之后,这个人就正式存在了。有了这些记录,政府就可以对这个人进行各种管理了。
与一个社会管理人的过程类似,操作系统要管理进程就要维护关于进程的一些信息。当一个进程产生时,操
作系统也需要为其创建记录。操作系统用于维护进程记录的结构就是进程表或进程控制块(Process Control
Block, PCB)。这个进程表或PCB中存放的就是有关该进程的资料。那么进程表里有什么资料呢?显然,不
同的操作系统维护的进程资料不尽相同。但一般来说,维护的资料信息应当包括寄存器、程序计数器、状态
字、栈指针、优先级、进程ID、信号、创建时间、所耗CPU时间、当前持有的各种句柄等。而采纳的数据结
构主要是线性表、链表和结构(struct),当然也可能使用树和图(网络)结构。例如,Solaris的进程表就使
用了上述4种数据结构。表4-2描述的是一个高度简化的进程表。
这个进程表保持在操作系统所在的内核空间里,如图4-7所示。图 4-7 进程表存放在操作系统所在的内核空间里
如果想更深入地了解进程表的结构,读者可以参阅相关商业操作系统的内核教程。4.8.2 进程的创建过程
前面说过,对于一个计算机系统来说,不断创建和终结进程,创建进程和终结进程各有4种方法。但操作系
统是如何创建一个进程的呢?一般来说,创建进程的步骤如下所示:
1)分配进程控制块。
2)初始化机器寄存器。
3)初始化页表。
4)将程序代码从磁盘读进内存。
5)将处理器状态设置为“用户态”。
6)跳转到程序的起始地址(设置程序计数器)。
这里一个最大的问题是,跳转指令是内核态指令,而在第5步时处理器状态已经被设置为用户态,但在用户
态下是不能执行内核态指令的。这个问题如何解决?当然了,这就需要硬件帮忙了。硬件必须将第5和第6两
步作为一个步骤一起完成。
进程创建在不同的操作系统里方法也不一样。例如,UNIX将进程创建分为两个步骤:第1步是fork,创建一
个与自己完全一样的新进程;第2步是exec,将新的进程的地址空间用另一个程序的内容覆盖,然后跳转到
新程序的起始地址,从而完成新程序的启动。而Windows使用一个系统调用就可以完成进程创建。这个系统
调用就是CreateProcess。在调用该函数时我们把欲执行的程序名称作为参数传过来,创建新的页表,而不需
要复制别的进程。
UNIX和Windows的进程创建过程各有优缺点。UNIX的创建过程要灵活一些,因为我们既可以自我复制,也
可以启动新的程序。而自我复制在很多情况下是很有用的。例如,Web服务器在每收到一个用户请求后,就
创建一个新的一模一样的进程来服务用户请求。而在Windows下,复制自我就要复杂一些了。而且,共享数
据只能通过参数传递来实现。4.8.3 进程管理要处理的问题
进程管理的最大问题是资源分配。那么如何分配资源呢?人类社会最大的问题也是资源分配。谁能解决资源
争端,让地球上每个人高高兴兴地共享资源,谁就是人类的救星。当然,计算机的资源分配问题不像人类那
样困难,因为程序没有自我意识,就算我们对某些程序不公平,它们也无法抱怨。但这不能成为我们偷懒和
堕落的理由。毕竟,我们制造计算机就是想好好地利用它,自然希望能够让所有进程高兴地相处在一起。毕
竟,我们的本性还是追求公平的。
除了公平之外,还有一个问题要考虑:效率,也就是最优。每个进程分配同样的资源肯定不行。以前32个终
端连到一台计算机上,慢得不行,结果没有任何人高兴。不如让部分人先富起来,给他们使用资源的优先
权。
这样,公平与效率就成了进程管理中永恒的主题。到底是公平重要,还是效率重要?天平的不同倾斜将引出
十分不同的进程管理模式。4.9 进程的缺陷
看上去,进程的抽象或模型似乎很好:既提高了系统利用率,又缩短了系统响应时间。它通过支持多道编
程,让我们感觉每个人都拥有自己的CPU和其他资源,似乎皆大欢喜。
难道进程模型就没有任何问题了吗?当然不是。
如果仔细观察,就会发现,进程有个很严重的问题。假定现在有两部很好的电影,都只放映一次,以后再也
不放映了。而且,这两部电影同时放映,当然了,是在不同的两个房间放映。而你很想将这两部电影都看
了,有什么办法吗?假定没有光碟刻录机也没有录像机等。
当然,我们没有办法同时看两部电影。这也是进程的缺点。它只能在一个时间做一件事情。如果想同时做两
件或多件事情,进程就不够用了。
另外,更为重要的是,如果进程在执行的过程中阻塞,例如等待输入,整个进程就将挂起(暂停),而无法
继续执行。这样,即使进程里面有部分工作不依赖于输入数据,也无法推进。
而为了解决上述两个问题,人们就发明了线程。本书将在第三篇对线程进行讨论。思考题
1.发明进程的根本动机是什么?它与程序是什么关系?请予以论述。
2.进程带给我们的最大好处是什么?它有什么缺点吗?
3.进程空间是什么意思?它包括哪些东西?它与进程是什么关系?
4.进程有哪3种状态,分别代表什么意思?
5.在进程的6种状态转换里有两种是不存在的,但它们不存在的理由却不一样。请予以解释。
6.在商用操作系统里,进程的状态通常多于3个,请问,设置多于3个进程状态的可能原因是什么?
7.操作系统管理进程的根本手段是什么?
8.进程管理时的两个重要考虑是公平和效率。除此之外,还有什么因素需要考虑吗?
9.进程的产生与消亡与人的出生与消亡有着某种类比性,你能否予以阐述?10.多道编程是否总能提高CPU的
利用率?为什么?
11.有同学认为在进程状态的6种转换中,从就绪到阻塞在理论上可行(操作系统将就绪进程的状态改变为阻
塞状态),而从阻塞到运行则在理论上不可行,你同意吗?为什么?
12.分析:在内核态下的进程通常共享一个地址空间,这是为什么?第5章 进程调度
引子:恐怖分子的调度
1970年的冬天,加拿大魁北克省渥太华的皇家骑警总部。来自美国联邦调查局、美国中央情报局、加拿大皇
家骑警、加拿大安全情报局的特工和警察领导正在这里举行紧急会议。
一个星期前,一群来自欧洲和中东的政要及大亨在美国乘坐由美国政府安排的列车游览美国壮丽河山的时候
被一群恐怖分子劫持。这列掌握在恐怖分子手中的高级列车已经在美国广袤大地上游荡了一个星期。恐怖分
子身上携带有生物病毒,他们以这些病毒和被他们控制的西方人质作为筹码,要求美国政府在政治和经济上
作出让步,但美国政府一直在口头上虚与委蛇,暗中却布置警察和特工对列车进行了多次反劫持行动,不过
皆没有成功。美国政府的行动激怒了恐怖分子,他们杀死了几名政要,并扬言释放生物病毒。情况万分危
急。
在恐怖分子的要挟下,列车进入了加拿大,在加拿大更加广袤的土地上游荡。恐怖分子继续与美国、加拿大
政府交涉。在加拿大皇家骑警总部召开的会议就是来讨论这列列车的问题。
......
您现在查看是摘要介绍页, 详见PDF附件(18140KB,427页)。





