内容
操作系统的过去、现在和将来
简介: 从三个角度分析操作系统发展的轨迹,预测未来智能化操作系统的发展过程。然后提出支撑结构的概念,以归纳现有操作系统模型,分析现有模型的共同点和未来模型的突破口,并进一步描述实现智能化操作系统前所需完成的任务。
操作系统的发展过程是一个从无到有、从简单到复杂的过程在这里我们从三个角度来观察操作系统的发展历史,硬件发展的角度、软件发展的角度、进化的角度。
操作系统的理论是在计算机的应用中诞生并成长,它的发展与计算机硬件的发展是密不可分的,这些内容多数教材上都有,这里就简单的罗列一下:
年 代 | 硬 件 特 点 | 操作系统特点 | 背 景 |
机械计算机时代 17世纪~20世纪初 | 1)纯机械结构,低速 2)只能进行简单的数学运算 | 纯手工操作 | 从计算尺至差分机到分析机发展了数百年 |
第一代计算机 1946年~50年代末 电子管计算机 | 1)体积大、能耗高、故障多、价格贵 2)难以普及应用 | 无操作系统 (程序按机器码编写,载体从插件板到卡片与纸带) | 1906年发明电子管 1946 ENIAC研制成功 (第一台电子管计算机) |
第二代计算机 50年代末~60年代中期 晶体管计算机 | 1)采用印刷电路 2)稳定性与可靠性大大提高 3)批量生产成为可能 4)进入的实际应用领域但数量有限 | 1)单道批处理系统 2)系统以监督软件形式出现 3)作业处理按顺序方式处理 | 1947年发明晶体管 |
第三代计算机 60年代中期~70年代初 集成电路计算机 | 1)体积减小,性价比迅速提高 2)小型计算机发展迅速 3)进入商业应用 4)尚不适合家庭应用的需求 | 1)涌现大批操作系统 多道批处理系统、分时系统和实时系统 2)奠定了现代操作系统的基本框架 | 1958年发明集成电路 1971年INTEL发明微处理器 |
第四代计算机 70年代中~至今 大规模集成电路计算机 | 1)性能大幅度提高,价格不断下降 2)个人电脑成为市场的主角 3)电脑迅速普及 4)计算机应用进入高速发展的轨道 | 1)操作系统的理论基本完善 2)系统与网络通讯一体化 (分布式操作系统和网络操作系统) 3)人机交互成为设计重点 4)操作系统性能日渐稳定 | 1981年IBM-PC机诞生 1993年 INTERNET开始商业化运作 |
从这张表中可以看出:
- 在硬件的性价比较低的时候,操作系统设计完成了追求硬件使用率的理论探索,从批处理到分时系统
- 在硬件性价比越来越高后,操作系统的设计开始追求系统的可靠和稳定,出现了多处理器系统和分布式系统
- 电脑开始普及后,操作系统的设计开始追求用户界面的友好
- 从第一代到第二代计算机系统,应用范围很小,导致操作系统的发展非常缓慢,直到第三代系统出现后,才得以高速发展
- 从第三代计算机到第四代计算机,操作系统的功能模块划分没有变化,说明计算机硬件结构已经稳定,操作系统的发展逐渐脱离硬件的发展脚步,形成自己的理论体系
- 进入第四代系统后,分布式系统和多处理器系统虽然极大的扩充了操作系统理论,但系统结构仍旧保持不变,完善的部分是各功能模块的枝节理论
总的讲,随着操作系统理论的日益完善,操作系统设计中与硬件相关的部分比重越来越小,渐渐走出软件附属于硬件的局面,至今它已经支撑起一个庞大的软件产业
操作系统首先是一个软件,它的设计脱离不了软件设计的范畴,因此可以从纯软件发展的角度考察这里简单的从软件设计发展的过程分析操作系统的历史
主流系统 | 系统特点 | 计 算 机 语 言 | 软 件 特 点 | 背 景 | |
无软件时期 | 无 | 手工操作 | 无编程语言 直接使用机器代码 | 手工操作 | 1936年图灵提出图灵机 |
系统雏形期 | 单道批处理系统 | 作业运行的监督程序 | 编程语言雏形期 | 无交互机制 | 1957年 FORTRAN语言开发成功 |
操作系统的理论成形期 | 多道批处理 分时系统 实时系统 多处理系统 | 系统结构确立分为处理机、内存、设备、文件等模块 | 1)编程语言大量涌现 2)结构化程序设计 3)C语言逐渐成为主导 | 1)字符式人机交互界面 2)操作命令繁多 | 60年代的软件危机导致软件工程的发展 1970年 UNIX产生 1972年 C语言推出 |
现代操作系统时期 | 类UNIX系列 WINDOWS系列 | 人机交互成为主题 1)可视化界面 2)多媒体技术 | 面向对象语言取代结构化设计语言 | 1)过渡至图形界面 2)注重操作可视化 | 80年代中期面向对象技术逐步发展并替代了结构化设计 |
网络时代 | 网络操作系统 分布式系统 | 微内核技术兴起 | 1)JAVA语言 2)脚本语言兴起 | 追求设计个性化 注重感官效果 | 1995年JAVA推出 |
自由软件时代 | 嵌入式系统 | 单内核与微内核竞争激烈 | 编程工具向跨平台方向发展 | 可移植性成为主题 | 1991年免费的操作系统Linux发布 |
从这张表可以看出:
- 操作系统的发展滞后于计算机语言的发展,程序设计理论约束着操作系统设计,从结构化设计到对象化设计,操作系统总是最后应用新编程理论的软件之一(编译器也是如此)
- 至今操作系统是否彻底对象化(即微内核化),还处于徘徊时期,等待单内核与微内核最佳结合方式的出现
- 人机交互技术是一个从用户角度对操作系统设计进行的变革
现有的操作系统设计应当寻找新的突破点,摆脱被动跟随程序设计理论的突破而突破,毕竟编程理论只是软件的基础,而现在的操作系统发展进入一个平稳期,各种枝节理论迅速发展并稳定,为总体结构突破提供了良好的基础。
硬件发展轨迹和软件发展轨迹,是对过去发展的分析,对未来发展方向的预测,则要换一种思路。
从算盘到现在的计算机,每个时代的人都追求着同样的目标,把人从复杂计算中解脱,且都幻想着能制造一种具有人类智能的机器。
计算机的诞生和迅猛发展,使得机器是否能思维的问题,就真实的摆在了我们面前,何时计算机能够真正地模拟人类的智能。
早在1950图灵就提出"机器思维"的概念,证明机器能否思维,关键在于如何定义思维,并提出"图灵测试"。
如今我们的任务应该是如何让计算机具有思维。
人工智能的发展,已经使得应用软件的智能化成为可能,虽然还比较初级。
作为计算机系统的核心操作系统,其智能化的研究还很缓慢,本系列就是探讨操作系统如何向智能化的发展
现在的操作系统是处于发展的哪个阶段呢?
先看一个类比,操作系统的发展过程与地球生命进化过程之间的类比。
(注:引用进化观念是一种概念分析手段,并无意参与有关进化论是与非的争论)
操作系统的历史 | 生命的进化历史 | |||||
操作系统过去与现在 | 无操作系统时期 (从机械式到电子管) | 完成硬件设计的探索 | 初级生命体时期 (原核细胞、真核生物) | 对生命存在方式的探索 | ||
初级操作系统 --批处理系统 | 原始的操作系统软件 | 寒武纪之前 (软体后生动物) | 原始海洋生物 | |||
理论成形期 | 大量结构化设计的操作系统出现 | 古生代早期 (无脊椎动物) | 寒武纪时期的生命大爆炸 | |||
理论完善期 个人系统占主导 | 面向对象理论迅速发展 | 古生代晚期 (生物登陆) | 从无脊椎到有脊椎的进化 | |||
网络时代 网络与系统的融合 | 单内核与微内核初期竞争 | 中生代 (爬行类动物) | 典型代表:恐龙 | |||
自由软件时代 | 高级系统结构的探索 | 新 生 代 | 6500万年前哺乳动物开始主宰地球 | 出现简单的脑结构 高级动物种类的繁荣 | ||
未来的发展 | 未 知 | 数百万年前进入类人猿时期 | 能够直立行走 形成与人相似的大脑结构 | |||
未 知 | 二十万年前~四万年前古人类时期 | 真正意义上的智人出现 | ||||
未 知 | 四万年前~现今 现代人类 | 人类社会的形成并发展 |
相比较,现在的操作系统正处在第二次繁荣期(第一次繁荣是60年代~70年代,理论的形成期),大量不同种类的操作系统和相关技术不断涌现,而微内核和单内核的竞争是操作系统结构走向成熟的开始
操作系统一栏中有数个与人类进化对应的空格代表着操作系统未来的发展方向
未 来 的 操 作 系 统 | 生 物 进 化 的 历 史 | ||||
智能结构的探索期 | 开放源代码运动 | 为操作系统发展培养人力资源 | 新 生 代 | 现代哺乳动物开始主宰地球 | 高级动物出现 |
智能化系统结构 人工智能与操作系统的初级结合 | 动态变化的操作系统结构设计 | 类人猿时期 | 基本和人相同的组织结构 | ||
智能操作系统 | 知识库的积累 | 具有学习功能 | 古人类时期 | 人类的发展 | |
真正意义上的自主式系统 | 自动编程功能 | 现代人类社会的出现 |
发展初期是软件适应硬件的过程,如同生命初期为适应地球环境而做的努力
发展中期是操作系统理论的形成,逐步与硬件细节分离,产生自身的特性
发展的后期是形成完善的操作系统结构
这些发展都是为最后智能化做前期准备,如同生物进化至人类祖先的出现
是一个探索系统最合理结构的过程
最后一步是智能化,但却是最漫长的一步,和生物进化产生人类智慧的进度刚好相反
从每个阶段发展的时间长度看,生物进化与操作系统向智能化发展时间比例刚好相反
图1.1 生命进化示意图
图1.2 操作系统的发展示意图
虽然,关于生命起源和进化的过程还是有很多争议,但不影响在此引用,因为操作系统的发展是我们可以掌握和控制的,不是象生物进化那样只有化石了。
计算机系统从一开始就是向着模拟人类智能的脚步前进的。
只是现在处于一个高度细分的工作环境下,容易产生智能软件是应用层,而操作系统是基础软件的分工。
从80年代开始发展的自主式智能系统总是定位在应用层,较少涉及操作系统领域。
而通过这一类比,可以简要地说明要智能化操作系统,必须先形成一个能容纳智能的结构--"脑"。
现有的操作系统理论是今后智能系统的"肢体"部分,在形成"脑"结构后,自主式操作系统才从结构上完成进化,成为"类人猿",此时现有的自主式智能系统便能成为"脑"的一部分,自如的控制"肢体"。
从机器人的角度考虑,操作系统智能化过程是形成机器人"大脑"的一个过程,这点将在后续的《一体化》一文中论述。
通过上面的比较,想说明如下几点;
- 微内核的出现,使操作系统的基本结构日趋完善,但并没有产生质变
- 下一阶段的操作系统质变是形成有"智能"潜力的结构
在第五代计算机出现之前,操作系统的理论已经能够从硬件单向制约软件状态转向软件反向推动硬件发展,如今这点表现为商业应用推动了计算机外设的发展,今后将表现为硬件设计中的灵活性,如现在已经出现微指令能动态设计的处理器,这些将在后续文章中另作讨论,因为它们还不足以真正变革操作系统,只能局部改变操作系统的模块,而且也只有当智能化概念引进后,才能更好的利用这些功能。
在进一步预测未来系统前,先分析现今操作系统的基本结构。
操作系统发展至今模块结构已经非常明确,即处理器管理、存储器管理、设备管理和文件管理统
处理器管理 | CPU |
存储器管理 | 内存、高速缓存 |
设备管理 | 所有需要驱动程序的设备 |
文件管理统 | 各种大小容量的存储设备 |
只有文件管理系统是属于建立在存储器上的逻辑管理功能
因此可以说现今的操作系统是一种直接的计算机硬件的逻辑映射,即现在的操作系统模型是硬件组合模型的软件表达式。
所以从这个角度讲现在的操作系统理论发展还没有真正形成自己的理论,从整体上看还是一个大的设备管理系统
在此希望通过对现有模型的分析,找出理论突破的方向。
操作系统最基本的结构是模块结构和层次结构。
模块结构就是最一般的结构化设计,单内核就是模块结构,但内核的概念是一种层次概念。
而层次结构是建立在系统功能模块分类的基础之上,是一种模块集合作为'层'的结构。
现代的操作系统结构都是模块概念的衍生物。
而理论上形成的操作系统几大功能模块就是进行了一次逻辑分层的工作,因此,不再独立讨论模块结构。
现代操作系统按模块间功能调用方式分:
有两种系统模型: 单内核与微内核。
另外还有两种应用模型: 虚拟机与客户/服务器模式,它们是建立在操作系统上的系统应用扩展模型。
提出系统内核概念就是一种层次概念,层次概念能很好的从理论上进行功能的划分,如将操作系统代码分成体系相关部分与体系无关部分,及应用接口部分(为体系相关部分,但多数体系相关部分为涉及硬件底层的代码)。
如图:
应用软件层 |
应用接口层(API) |
体系无关层(逻辑管理层,如:进程调度、内存管理等) |
体系相关层(设备驱动层) |
硬 件 层 |
这是系统设计中的层次结构,而用户进程与内核进程则是运行态中层次概念。
因为是小到两个变量或函数之间的关系,大到软件集之间的关系都能称为层次。
由此如今的系统内核概念的提出就是层次关系最好的体现。
A能调用B而B的实现与A无关,可以认为A永远处于B的上一层,一种静态层次。
当A与B互为调用时,可以认为是动态的层次关系或对等层次,如同客户服务器的概念就是这样的层次概念。
在结构化设计中,层次概念由模块组合来表达,在对象化设计中,层次概念由对象集合来表达,在不同的设计理论下,有着不同的表现方式。
因此,层次模型是最基础的模型,其它的模型都是层次概念在不同设计理论下的变换。
从最初的操作系统设计开始,操作系统就是单内核的形式,以结构化程序设计理论为基础,至今在多数操作系统模型中单内核依然拥有主导地位
单内核--集中式操作系统,整个系统是一大进程,可以被分为若干逻辑模块,即处理器管理、存储器管理、设备管理和文件管理,但在运行时,这些模块仅构成一个进程,其模块间的连接是通过直接调用其他模块中的函数来实现。
因此现今的单内核是一种整体式层次结构。
单内核模型以系统执行效率为设计核心,因为整个系统是一个统一的内核,所以其内部调用效率很高,但对于远程调用来说同样没有优势。
单内核的系统缺点也正是由其源代码是一个整体而造成的,通常其模块之间的界线并不是特别的清晰,模块间的调用比较随意,所以做系统修改时,往往牵一发而动全身,导致工作量大,维护困难。
微内核是面向对象理论在操作系统设计中应用的产物,在实际应用中,微内核尚处于发展阶段。
微内核 -- 把操作系统结构中的内存管理、设备管理、文件系统等高级服务功能尽可能地从内核中分离出来,变成几个独立的非内核进程,使内核功能变得简洁可靠,而各独立模块以特权方式的用户进程出现,具有各自独立的运行空间,模块间以IPC(进程间通讯)方式来完成单内核中相同功能的调用。
微内核实现的基础是操作系统理论上的逻辑功能划分,几大功能模块在理论上是相互独立的,在长期的单内核设计中内核设计逐渐按逻辑划分,形成比较明显的界限,使得微内核概念脱颖而出。
微内核通常仅负责少量的功能:
- 进程的管理和调度
- 进程间通讯
- 内核自身所需内存的管理
- 部分必须的基础设备管理
微内核简单的讲是一个消息的转发站,因此也可以说微内核模型是从客户服务器模型转换而来的。
优点:
- 充分的模块化,使得模块独立更换而不影响其它模块,方便了第三方的开发者设计模块
- 未被使用的模块功能不必运行,因而能大幅度减少系统的内存需求,从另一个角度降低了虚拟内存管理的负担
- 具有很高的可移植性,理论上讲只需要对微内核部分进行移植修改即可,而微内核的体积通常很小,因此花费小
- 模型方式适合于建立分布式操作系统
缺点:
- 使用通讯方式完成功能调用,速度低得多
- 对于单处理器系统,模块间独立地址空间的切换频繁,对整体性能影响较大
图2.1 微内核示意图
虚拟机是一种仿真概念,源自于大型机,在一定硬件功能支持下,以软件方式模拟低速处理系统的硬件,形成一个软件模拟的虚拟机系统,使得那些低速系统上的软件能够直接在大型机上运行,减少了软件移植的工作量。
对于主机而言本身也拥有一个独立的操作系统,而虚拟机是建立在这个操作系统上的一种应用软件。
图2.2 虚拟机示意图
以虚拟机的方式可以使用较少的工作量来实现大型机上的跨平台软件移植,只对需移植的操作系统进行少量与设备相关的修改,甚至不必修改即可运行。
JAVA虚拟机的概念是一种简化的虚拟机,因为它本身的出发点就是建立在解释器上的通用平台系统,自身的实现必须依赖操作系统的功能,是一种应用系统。如将基本的操作系统内核与JAVA虚拟机融合,则JAVA虚拟机就成为真正的操作系统,适合于嵌入式系统。
单从软件角度看,虚拟机是仿真技术的一种,这种方式可以简化成一种安全系统的子系统,模拟主系统主要结构,用于检测可疑代码,以保证在主系统中代码的安全性,这点将在后续的文章中讨论。
客户服务器模型是一种建立在操作系统内核基础上的应用模式,是网络操作系统发展的产物,这种模式将调用分成请求和应答两个部分,分别由客户端产生向服务器的请求,服务器端生成应答回送给客户端。
如图:
图2.3 客户/服务器模型示意
客户端和服务器端并没有严格的区分界线,当某服务器需要其他模块帮助完成某个任务时,它就成为发送请求的客户端 客户端与服务器端也可以在同处于一台机器中,建立在同一系统内核之上。
这种模型以网络通讯或本地通讯为基础,所以此模型常用于网络操作系统和分布式操作系统中。
从示意图中可以看出,客户服务器模型与微内核模型有本质上的类似,差别只是客户服务器模型的应用面更广 从操作系统的层次结构讲,所有的操作系统模型都是客户-服务器模式在不同程度上的组合。
在实际的操作系统中,很少有完全符合的微内核理论划分的系统,总是为了提高效率作了一定的改变 有个现象很有趣,就是现有的单内核系统多少都拥有一定的微内核特征,而且越来越多 多数操作系统的发展都是侧重某个模型,并将两种模型的优势进行一定程度上的融合。
在此主要分析微内核与单内核:
微内核是在单内核的基础上分化而来的,主要变化是将原本在单内核中融为一体的内核中的功能调用,以一张内核调用表来联系各内核模块,模块间功能调用以该表中描述的功能序号和调用参数格式为依据,使用通讯方式传递调用命令。
因此微内核与单内核从结构上定有本质上的相同点。
分析前,先引入一个重要的概念 -- 软件的支撑结构。
在软件设计范畴中定义两个概念 -- 支撑点与支撑结构
它们是操作协议概念在软件设计中一种具体化的形式 (本系列的第一篇文章中有关于操作协议的详细定义)
假设集合A是一组已经实现的功能模块与变量,而集合B是这样一组功能模块,其功能的实现是建立在对A的调用基础之上,则称A是B的一个支撑点的集合,A中的每个直接被B调用的元素都是B的支撑点。
按此定义,在编程中所有的设计人员定义的变量、函数、各种数据类型以及开发工具提供的库函数、类库都是程序的支撑点。
而支撑点又分内部支撑点和外部支撑点两种。
内部支撑点是指为实现某个功能集而定义的新的数据,属于功能集。
外部支撑点是指为实现某个功能而调用的外部功能集合中的数据。
例如,对单个函数而言,函数内部定义的局部变量就是此函数的内部支撑点,而其调用的外部变量和函数就是此函数的外部支撑点。
图2.4 支撑点集合示意图
其中使用规则是一套的内部支撑点和外部支撑点选择和使用的规则,它由设计者来定义,通过编程的语句来表达,由设计者将规则融合进代码,是软件设计者或设计小组,根据系统的自身要求定义的,是一种便于内部协作的内部操作协议。
内部支撑点和外部支撑点是程序设计的基础(多数程序员并没有意识到自己在使用它,但不影响设计),整个软件项目开发的过程就是一个内部支撑点集和外部支撑点集博弈的过程,即圈定外部支撑点集合与内部支撑点集合的过程,这个过程通过使用规则的完善过程得以体现。
而使用规则的完善过程正是软件工程理论应用的过程,规则设计方法的变化过程是软件工程理论发展的过程。
对于操作系统设计而言,支撑点的概念略显不足,因为操作系统发展至今已经有一定的理论框架,其基本功能均被圈定,而支撑点的概念主要凸现的是一个设计者自己的设计发挥,如同单个函数的设计,其内外部的支撑点选定具有很大的灵活度,因此提出支撑结构的概念,以用于分析操作系统模型。
对操作系统设计人员来讲,硬件标准就是编程的一个支撑点集合,对于应用软件设计人员来讲,操作系统提供的编程接口(API)就是一个编程的支撑点集合,这两种支撑点的共同点在于它们对使用者而言是一种标准(在一定范围内),而且能保持较长时间的不变性,相对而言是静止的,因此称这样的支撑点集合形成的是支撑结构,支撑结构是实际产品中与系统模型结构相对应的结构,是产品的骨架。
支撑结构是一种相对静止的概念,是操作协议概念在软件设计中一种具体化的形式,是软件设计内部的约束形式。
如同编程接口相对程序员是静止的,系统调用表对应用软件是静止的。这些静止体现了计算机系统的软件层次结构,正是有了这种相对静止,使软件设计得以详细分工, "相对静止"是一种动态的概念,因为存在变化中的差异,才能存在相对中的静止。
支撑结构分为两种:静态支撑结构和动态支撑结构。
静态支撑结构 -- 构成支撑结构的支撑点集合是静态集合,对产品而言是保持永久不变的,因此支撑结构是一组静态数据集合,集合的定义规则处于设计者的大脑中。
动态支撑结构 -- 构成支撑结构的支撑点集合是动态集合,在产品使用中保持动态变化,因此结构是以一组支撑点选择规则为核心的自动生成相应支撑点集合的机制,也就是说,将静态支撑结构中集合定义的规则,从设计者的大脑中,以实际描述的方式予以表达,而设计者大脑中保留的是规则的定义方式。
静态支撑结构和动态支撑结构之间的本质差别在于使用规则和规则定义的方式
如图:
从示意图中可以看出动态支撑结构使得系统模型变得很复杂,而且规则模型是很抽象的概念,难以具体描述。
(什么是规则与规则模型,将在《规则量化》中描述,但以概念讨论为主,作为思维量化的探索)
动态的支撑结构就是把静态支撑结构变成可变的结构。
那静态支撑结构具体是什么?
现有的操作系统模型,其系统模型是建立在静态的支撑结构之上,即整个操作系统的模型是静态模型,建立后不再修改,若修改就形成一个新的操作系统版本。
可以从下面的分析中看到一种具体的静态支撑结构。
以支撑结构的概念来分析单内核与微内核,就可看到它们之间的一致性。
微内核以静态的内核调用表为其通讯的基准,得以实现模块之间的调用,而微内核中各独立模块的代码仍旧是高度集中的。
如图:
图2.7 微内核式操作系统的模型图
例如MINIX中模块间调用是通过如下方式分解消息来实现的。
在此摘录部分源代码进行分析。
(注:《OPERATING SYSTEM Design and Implementation》第二版,Andrew S.Tanenbaum 和Albert S.WoodHull著)
以下MINIX系统中内存管理模块的main.c文件的一部分
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/mm/main.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 16600 /* This file contains the main program of the memory manager and some related 16601 * procedures. When MINIX starts up, the kernel runs for a little while, 16602 * initializing itself and its tasks, and then it runs MM and FS. Both MM 16603 * and FS initialize themselves as far as they can. FS then makes a call to 16604 * MM, because MM has to wait for FS to acquire a RAM disk. MM asks the 16605 * kernel for all free memory and starts serving requests. 16606 * 16607 * The entry points into this file are: 16608 * main: starts MM running 16609 * reply: reply to a process making an MM system call 16610 */ 16611 16612 #include "mm.h" 16613 #include . . . 16624 /*===========================================================================* 16625 * main * 16626 *===========================================================================*/ 16627 PUBLIC void main() 16628 { 16631 int error; 16633 mm_init(); /* initialize memory manager tables */ 16636 while (TRUE) { 16638 get_work(); /* wait for an MM system call */ 16639 mp = &mproc[who]; 16642 error = OK; 16643 dont_reply = FALSE; 16644 err_code = -999; 16647 if (mm_call < 0 || mm_call >= NCALLS) 16648 error = EBADCALL; 16649 else 16650 error = (*call_vec[mm_call])(); 16653 if (dont_reply) continue; /* no reply for EXIT and WAIT */ 16654 if (mm_call == EXEC && error == OK) continue; 16655 reply(who, error, result2, res_ptr); 16656 } 16657 } 16663 PRIVATE void get_work() 16664 { 16665 /* Wait for the next message and extract useful information from it. */ 16666 16667 if (receive(ANY, &mm_in) != OK) panic("MM receive error", NO_NUM); 16668 who = mm_in.m_source; /* who sent the message */ 16669 mm_call = mm_in.m_type; /* system call number */ 16670 } |
其中它定义了一个函数指针数组call_vec[NCALLS],保存相应系统调用的函数指针,功能的顺序是静态定义的,通过get_work()分析消息得到系统调用号mm_call,然后执行error = (*call_vec[mm_call])();来完成请求。
而call_vec[]是一静态向量表的定义如下:
(同一书中的源代码)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/mm/table.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 16500 /* This file contains the table used to map system call numbers onto the 16501 * routines that perform them. . . . 16515 _PROTOTYPE (int (*call_vec[NCALLS]), (void) ) = { 16516 no_sys, /* 0 = unused */ 16517 do_mm_exit, /* 1 = exit */ 16518 do_fork, /* 2 = fork */ 16519 no_sys, /* 3 = read */ 16520 no_sys, /* 4 = write */ 16521 no_sys, /* 5 = open */ 16522 no_sys, /* 6 = close */ . . . 16592 do_sigreturn, /* 75 = sigreturn */ 16593 do_reboot, /* 76 = reboot */ 16594 }; |
同样的函数调用方式在MINIX系统的文件管理模块也有:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/fs/main.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 22500 /* This file contains the main program of the File System. It consists of 22501 * a loop that gets messages requesting work, carries out the work, and sends 22502 * replies. 22503 * 22504 * The entry points into this file are 22505 * main: main program of the File System 22506 * reply: send a reply to a process after the requested work is done 22507 */ . . . 22515 #include . . . 22534 /*===========================================================================* 22535 * main * 22536 *===========================================================================*/ 22537 PUBLIC void main() 22538 { 22539 /* This is the main program of the file system. The main loop consists of 22540 * three major activities: getting new work, processing the work, and sending 22541 * the reply. This loop never terminates as long as the file system runs. 22542 */ 22543 int error; 22544 22545 fs_init(); 22546 22547 /* This is the main loop that gets work, processes it, and sends replies. */ 22548 while (TRUE) { 22549 get_work(); /* sets who and fs_call */ 22550 22551 fp = &fproc[who]; /* pointer to proc table struct */ 22552 super_user = (fp->fp_effuid == SU_UID ? TRUE : FALSE); /* su? */ 22553 dont_reply = FALSE; /* in other words, do reply is default */ 22554 22555 /* Call the internal function that does the work. */ 22556 if (fs_call < 0 || fs_call >= NCALLS) 22557 error = EBADCALL; 22558 else 22559 error = (*call_vector[fs_call])(); 22560 22561 /* Copy the results back to the user and send reply. */ 22562 if (dont_reply) continue; 22563 reply(who, error); 22564 if (rdahed_inode != NIL_INODE) read_ahead(); /* do block read ahead */ 22565 } 22566 } |
在文件系统中使用的是call_vector[fs_call],其定义如下:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/fs/table.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 20800 /* This file contains the table used to map system call numbers onto the 20801 * routines that perform them. 20802 */ . . . 20817 PUBLIC _PROTOTYPE (int (*call_vector[NCALLS]), (void) ) = { 20818 no_sys, /* 0 = unused */ 20819 do_exit, /* 1 = exit */ 20820 do_fork, /* 2 = fork */ 20821 do_read, /* 3 = read */ . . . 20894 no_sys, /* 75 = SIGRETURN */ 20895 no_sys, /* 76 = REBOOT */ 20896 }; |
而内存管理模块和文件管理模块中共同使用的include/minix/callnr.h如下:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/minix/callnr.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 03400 #define NCALLS 77 /* number of system calls allowed */ 03401 03402 #define EXIT 1 03403 #define FORK 2 03404 #define READ 3 03405 #define WRITE 4 03406 #define OPEN 5 03407 #define CLOSE 6 . . . 03462 #define SIGPROCMASK 74 03463 #define SIGRETURN 75 03464 03465 #define REBOOT 76 |
显然call_vec[]与call_vector[]是等同的静态向量表,也就是MINIX的内核之间的支撑结构,是静态的支撑结构。
各独立模块之间的相互调用是通过消息方式传递向量编号与相应的参数。
从以上分析可以看出,对于操作系统而言,静态支撑结构是一张静态的函数表。
在单内核系统中,这样的支撑结构是不明显的,因为其内核代码是一个整体。对于各种可按操作系统理论划分出的模块,它们之间是以直接函数调用来连接,也就是说单内核的各支撑点是分散在各个理论独立而代码不独立的模块中,由此这样的支撑点不会象微内核中的支撑点那样明显,以调用表的形式出现,它们已经直接融入代码之中,具有很大的可变性(因为模块间调用方式缺少事先的统一规定),由这些支撑点集合构成的支撑结构同样具有很大的可变性,只能在操作系统理论的划分上看出支撑结构的模型,这个支撑结构的模型与微内核的支撑结构是等同的,差别只在于结构中支撑点的调用方式。
因此单内核也拥有与微内核类似的模型图,只是通常设计之前并不会考虑这样的表的存在,而是在考虑模块时比较随意地制定了,因此单内核的函数表是一张制订比较随意的表,而且连接方式是直接的函数调用,不过其供应用软件使用的API是比较正规的,它也是支撑结构的一张映射表 。
也正是单内核中支撑结构的实际存在,才使微内核得以实现。在单内核中是一张复杂的关系表,在微内核中是一张简单明了的静态表。所以微内核中模块间复杂度的降低是因为在概念设计阶段就把系统支撑结构明确化了。
以系统模型支撑结构为核心,系统调用接口为对外的支撑结构为辅(构成一个编程界面),
图2.8 一般操作系统模型的支撑结构示意图
其中:
系统的支撑结构是一系列各模块提供的供其它模块调用的函数(但表达形式可以是消息参数方式)。
"对外的支撑结构"是操作系统为应用软件设计提供的API,也是一系列的函数。
如今的操作系统已经能够通过相对独立"对外的支撑结构"来实现应用软件的在不同操作系统下实现无缝移植,当然前提是硬件系统是兼容的,特别是处理器必须具有兼容的指令系统。
以支撑结构的概念来分析现有的操作系统,能得出如下结果:
- 操作系统,无论是何种以模型为系统主体,无论是一个程序构成,还是由程序集构成,都存在一个贯穿整个系统的支撑结构,整个系统的设计就是按照这个支撑结构展开
- 构成现有操作系统的支撑结构都是静态支撑结构
- 支撑结构是一张函数表,对于动态支撑结构而言,就是一张可动态的变化函数表
因此可以说单内核与微内核结构上是一致的,差别是模块间的联系,所以两者在理论上完全可以融合,只需在支撑结构上进行更灵活的设置。
例如:
把消息方式和直接函数结合,对于微内核模型,将本地模块之间的联系按直接调用方式结合,只在远程模块间使用消息方式,这样做并不是把微内核倒退至单内核,而只是改变消息方式的应用范围,这里需要编译功能的帮助才能完成,使得消息方式和直接调用方式能自由切换,这点将在下一篇文章中描述 如这样实现,微内核系统在本机内可达到与单内核相近的效率,在外部,仍可以通讯方式构造分布式系统。
智能化是未来操作系统趋势,但如何智能化?
如今自主式系统的概念已经发展多年,但实质仍旧是适应特定应用环境的专家系统,基本是建立在传统的操作系统之上的应用软件,侧重点是应用,而非操作系统领域。
按现有的软件应用方式,智能化操作系统有两种方案:
- 现有的操作系统模式 + 专家系统
智能模块作为一种应用软件,将自身定位于智能工具,主动权仍旧属于用户 - 将专家系统内嵌至操作系统中
以人工智能方式管理操作系统的运行,目标是形成能自我管理的系统,最终形成自主式系统
第一种方案是可以立竿见影的方案,能在短期内使得计算机系统看上去智能化了,但由于其核心操作系统并没有在智能化模块的管理范围内,就产生了如下缺点:
- 智能模块以应用软件身份运行,没有了主要设备的管理权,例如智能的更换主要设备(处理器、内存等等)
- 无法改变操作系统中存在缺陷,因为不能真掌握自身的运行过程,难以避免由操作系统错误产生的系统崩溃
第二种方案实现的最终结果是:
- 现有的操作系统模型变成一个智能化操作系统的"设备管理模块"
- 现有的专家系统模式成为智能化操作系统的"用户界面"
两种方案是相辅相成的
- 第二种方案的基础还比较遥远,所以第一种方案是很有必要的,它能够将各个行业的知识形成知识库,进一步促进人工智能的发展,为第二方案的实现打好基础
- 即使第二种方案实现了,第一种方案仍将存在,因为第二种方案的应用范围是在那些人工智能应用非常成熟的领域,对于尚不成熟的领域,第一种方案是很好的探索方式,所以,第一种方案必将成为第二种方案的一个子方案
关键原因就是现在的人工智能火候不够,尚没足够让人振奋的成果,难以看出实际大规模应用人工智能的方式,所以本系列是从探索的角度来分析未来智能操作系统的结构。
要实现第二种方案,先期有三方面的工作
- 系统结构智能化,转变成具有适合智能发展的"智能"结构
- 系统功能的参数化,为功能模块的智能化建造模型
- 转变编译器的应用形式,形成自动化编程的雏形
操作系统智能化的主方向是形成自主式操作系统,从第一章的分析可以看出,现在的操作系统正处于结构成熟期,但仅仅是硬件模型的直接转化,要形成自主式,需要一种新结构,是建立在现有逻辑结构上的"大脑"结构。
由现有计算机硬件的特殊性,无论如何智能化,所有功能还是得由机器指令一步步的完成,所以"智能化"结构中职能模块和非职能模块之间的联系核心是对处理器的控制权分配,如同人体结构中,如何通过大脑的反映来平衡其他身体器官的信号与人思考之间的冲突,大脑是人的"处理器"不仅得处理人体物理组织产生的信号,还要承担意识活动,而意识活动能在生理条件许可的范围内控制全身组织,并通过大脑处理反馈信号来修正意识活动。
但和人相比,计算机有其特殊性,它的硬件组织与人体器官一样是任何活动的基础,而软件设计拥有极大的灵活度,也就是说人对自身器官的管理多数是处于本能反应,而操作系统却能够在逻辑正确的情况下,灵活控制和改变。
从第二章的分析可以看出,虽然现在已经涌现出许多操作系统,但它们的本质仍旧是建立在类似的静态支撑结构之上,系统形成的规则依旧停留在人的大脑中,因此现有操作系统的结构是难以依靠自身的变化来突破。
这种情况导致现有的操作系统理论只是一些细节技术的堆积,而没有一个整体的理论环境,所形成的理论格局与硬件格局完全类似的地步。
如将系统结构改成动态的支撑结构,把现在停留在人脑中的系统理论变成可度量的计算机规则,操作系统的结构就能象水一样的柔,可自如的适应各种硬件需求和软件需求。
但形成可度量的规则本身就是一个智能化的难题。
新的系统模型将是本系列文章的下一篇的主题。
在那里,将描述一个简单动态支撑结构,它本身没有解决量化规则的问题,而是探索如何从现有系统模型向可变结构的发展。
参数化 -- 是一种分析过程,对现有功能进行重新分析,从功能实现中归纳出多个关键的可度化的量,并且通过这些量来准确反映整个功能活动过程中的主要特性,称这些量为功能参数,寻找参数的过程称为参数化。
参数化的目的是寻找出足够多的关键参数,为该功能构造一个数学模型,从而能以更全面的角度来动态控制整个功能的活动。
设计智能化系统结构的是为操作系统智能化提供实现的结构基础,而参数化后形成操作系统的数学模型,则是建立智能核心的关键。
参数化是一个量化的过程,参数化和数学模型建立是两个同时进行的相辅相成的过程,有如下几个问题:
- 为何要参数化
- 如何定义参数化的规则,即参数的选择方案
- 被参数化的功能本身是否存在结构缺陷,如何判断
- 如何通过参数化来完善功能结构
- 数学模型的基础是什么
- 建立数学模型要解决什么问题
从支撑结构的角度看,参数化的过程是对原有操作系统的支撑结构进行深入地量化分析,而建立数学模型是构造新型支撑结构的基础。
参数化的概念将是本系列中第四篇文章的主题。
编译器是与操作系统同等重要的系统软件,表面上看编译器理论与操作系统理论并没有多大相关性,编译器总是局限在将程序代码翻译成可执行代码的范畴内,对于操作系统来讲,它只是操作系统最终形成代码的最后一步。
- 操作系统模型的任何创新都必须有编译器的支持 如同以对象方式重建原有结构化的操作系统,必须要先有支持对象设计的编译器
- 可变的操作系统结构需要相应的编译功能支持
- 现今编译出错后的调试过程仍属于手工操作,完全依赖人脑的主动判断,要形成系统自动查错,甚至纠错功能,必须逐步把现有的设计过程(即编程、编译、查错过程)从手工方式过度到自动方式
对于具有动态支撑结构的系统,其长期目标是能根据规则自动生成系统,最终能分析自身系统进而改善形成规则,重新构造系统,形成一个自我进化的螺旋上升的系统完善过程。
这样的目标需要系统拥有自动的查错并纠正机制,是编译理论和操作系统设计理论逐步融合的长期过程,从某种意义上讲这与现今一些研究者提出的智能化编译器类似(指能自动分析人提出的问题并自动编程形成最终的应用程序,即未来的智能化的编译器)。
在本系列的讨论范围中,只是简单地描述两种理论的融合,而如今的编译理论与操作系统理论相距甚远,只是在操作系统部分结构设计中需要它的参与,因此暂不纳入本系列文章的范畴,只是在相关部分中有一定涉及。
现在的计算机系统主要任务是帮助人们勾通和思考,未来的计算机系统将会智能化, 它们的智能水平能发展到何种程度,是否会威胁到人的存在,这里简单的讨论一下这个问题。
1997年IBM的深蓝(Deep Blue)计算机战胜国际象棋世界冠军卡斯帕罗夫, 这说明了一点,只要是可以量化的思维形式,计算机总能处理的比人好,因为它高速、稳定,而且今后会更高速更稳定。 表面上看深蓝执行的代码是人工编制的,可以认为深蓝借了众人的力量战胜了世界冠军, 但程序编制的过程是一个量化思维的过程,即今后设计思维足够量化后,自动编程就自然可行了,那时计算机也能进行类似的量化思考,所以人工编程并不能帮我们抵挡人工智能的威胁,它只是现今人工智能不发达的表现。
问题的关键是人类的思维中有多少是不能够被量化的? 而那些不能被量化的形式就是未来人类与人工智能抗衡的最后底线, 但它们是否能抵挡住人工智能对人类智能的挑战,却依然是无法肯定的。
回顾一下,第一章第三小节中的两张图:图1.1与图1.2,一个是递减,一个是递增,是否有一个交点,恰好是人工智能逼近人类智能的转折点? 人的智能正随着时间的推进而积累,而人工智能也随着时间的推进而逐步逼近人的智能,哪个速度更快?
如今我们正处于发展的初期,很难预料结果,但一点是可以肯定的。
就是对于技术来讲,有如下一个两难的处境:
- 如果人工智能发展到和人类智能同等或略差点,必然对人类自身的生存造成威胁
- 如果最后发现人工智能无法达到基本的人类智能,那将是人类对自身探索的失败,也是我们无法忍受的
总的看来,逼近人类智能是个漫长的过程,但绝非不可能,到了某一天,它就会象现在的克隆人那样被大家恐惧了。
From:http://www.ibm.com/developerworks/cn/linux/theory/os/explore/part2/index.html