计算器曾经是真实器物,后来成了手机应用。与之相比,计算机本质上没有特别多不同之处。计算机如今能以高达每秒十亿次的极快速度做算术[1],但在20世纪70年代,运算速度远远低于每秒百万次。

20世纪60年代和20世纪70年代典型的计算机有一个由数十种指令组成的指令集,它可以执行:算术(加、减、乘、除),从主存储器中读出信息,将信息保存到主存储器,以及与磁盘或其他连接设备通信。另外还有一件至关重要的事:其中有一些指令负责依据之前的计算结果,即已做完的事,决定后续执行什么指令——这决定了计算机下一步做什么。这样一来,计算机就掌控了自己的命运。

指令和数据存放在同一个主存储器中,这个主存储器通常被叫作RAM,也就是“随机存储器”(random access memory)。将一系列指令装载到RAM,计算机就会根据指令内容执行不同任务。这就是你点击Word或Chrome浏览器图标时发生的事——操作系统将那个程序的指令装入内存,开始运行。

使用某种编程语言,为执行某项要完成的任务创建操作序列,这就是所谓的编程。直接创建所需指令是有可能的,但这项工作实在繁难,哪怕是写很小的程序也是如此,所以编程领域的大部分进步都与创造接近人类表达计算方式的编程语言有关。称为编译器的程序(当然得先把它写出来)将高级语言(接近人类语言)翻译为针对特定类型计算机的指令序列。

归根结底,如同Word或浏览器等普通程序一样,操作系统也是由那些指令构建而成的,只是它更为庞大和复杂。操作系统的任务是控制所有其他要运行的程序,并管理它们与计算机其他部分的交互。

这样讲太抽象了,用一个具体的小例子来说明什么是编程吧。假设我们想根据矩形的长和宽计算其面积。用人类语言可以这样说:“面积是长和宽的乘积。”学校教师会在黑板上写出面积计算的公式:

面积 = 长×宽

使用较高级别的编程语言时,我们会这样写:

area = length * width

这就是今天大部分主流编程语言中的确切形式。编译器将其翻译为人类仍然可读但主要面向计算机的机器指令序列。在一台虚构的简单计算机上,该序列大概像下面这样:

load length multiply width store area

最终,称为汇编器(assembler)的程序把该序列转换为人类不易读懂的指令。这些指令能够被载入计算机的主存储器。执行时,它们根据长和宽算出面积。当然这里没谈及很多细节(如何指定编译和加载,如何让长和宽的数值进入计算机,如何输出面积数值,等等),但本质大抵如此。

如果你想看看可工作的示例,以下这段完整的C语言程序输入长和宽,输出面积:

void main() { float length, width, area; scanf("%f %f", &length, &width); area = length * width; printf("area = %f\n", area); }

这段程序能在任意一台计算机上编译和执行。

每个人都至少知道Windows或macOS这些现代操作系统的名字,手机上运行的是Android和iOS等操作系统。

操作系统是控制计算机的程序,它给正在运行的程序分配资源。它管理主存储器,当运行中的程序有需要时,将主存分配给它们。在台式计算机或笔记本式计算机上,操作系统让你能够同时运行浏览器、文字处理器、音乐播放器,或许还有我们的面积计算小程序,并且按需任意切换到其中之一。

操作系统也控制显示,在收到程序请求时,使其在屏幕上可见。它还管理磁盘之类存储设备,当你保存Word文档时,文档就会被存下来,以备之后恢复并继续工作。

操作系统还负责协调与互联网之类的网络进行通信,这样你就能用浏览器搜索、与朋友联络、购物、分享宠物猫视频,一切齐头并进。

在程序发生错误时,操作系统保护其他程序不受影响,还要防止有害程序或用户误操作对系统自身造成的危害。

手机上的操作系统也是如此工作的。在底层,需要做许多动作来维持经由移动网络或无线网络的通信。虽然细节常有不同,但手机应用与Word这样的程序在概念上完全一样,并且用同样的编程语言编写。

现今的操作系统程序体量庞大,纷繁复杂。在20世纪60年代,它简单得多,但相对于同时代的其他程序,它还是既庞大又复杂。一般而言,IBM或DEC(Digital Equipment Corporation,美国数字设备公司)等计算机制造商为各种不同硬件提供操作系统。每个制造商生产的硬件全无共通之处,有时甚至来自同一厂商的硬件都会有很大不同,所以操作系统也各自不同。

更加麻烦的是,操作系统用汇编语言写成。汇编语言是人能读懂的机器指令,与特定类型硬件的指令集紧密相关。每种计算机都有自己的汇编语言,所以操作系统是庞大且复杂的汇编语言程序,每个操作系统都针对特定硬件、使用特定语言编写。

系统之间缺乏共通性,使用相互不兼容的低级语言,导致同时需要多个版本的程序:为某一操作系统编写的程序,在移植到其他操作系统或硬件架构上时,必须完全重写。这种状况阻碍了进步。如后文所述,Unix操作系统在所有类型的硬件上都保持一致,而且用较高级的语言写成,只需付出相对较少的成本,即可从一种计算机移植到另一种计算机。

Unix起源

贝尔实验室退出Multics项目后,项目组成员得找其他事来做。肯·汤普森(图2-2)还是想做操作系统,但实验室管理层被Multics伤透了心,不肯给操作系统项目买硬件。肯和其他人只能纸上谈兵,设计操作系统的各种组件,无法开展具体的实现工作。

unix有什么版本(Unix起源一周)(1)

图2-2 肯·汤普森,约1981年(杰勒德·霍尔兹曼供图)

恰在此时,肯找到一台没怎么用过的DEC PDP-7计算机。这种计算机的主要功能是做电路设计的输入设备。

PDP-7于1964年推出,但计算机领域演进太快,到了1969年,它已经过时。这台机器本身不算很强大,只有8K(8192)个18位字长的内存(16 KB),但其图形显示非常漂亮,所以肯就为它写了个太空旅行游戏。在这个游戏里,玩家可以漫游太阳系、探访各个行星。这个游戏有点让人上瘾,我玩了好几个小时。

PDP-7还有一个好玩的外设——磁盘驱动器高耸,直直架着一块磁盘。据传,万一盘片飞出来,站在它前面的人就有可能遇险。磁盘运转速度远高于计算机读写速度。为了解决这个古怪的问题,肯写了个磁盘调度算法来提升磁盘的总吞吐量。这个算法在任意磁盘上都可用,但主要是为PDP-7的这块磁盘设计的。

如何测试这个算法呢?这需要往磁盘上装载数据,肯认为他需要一个批量写数据的程序。

“在某一时刻,我发现离实现一个操作系统仅有3周之遥了。”他需要写三个程序,每周写一个:用来创建代码的编辑器;将代码转换为PDP-7能运行的机器语言的汇编器;再加上“内核的外层——操作系统齐活了”。

正在那时,肯的太太休了3周假,带着一岁大的儿子去加利福尼亚探望公婆,这样肯就有了3周不受打扰的工作时间。正如他在2019年一次采访中所说,“一周,一周,再一周,我们就有了Unix。”无论以何种方式来度量,这都体现了真正的软件生产力。

肯和我都从贝尔实验室退休几年之后,我问他3周内写出Unix是否属实。下面是他回复邮件的原文,谈到的情况和最近那次采访完全一致。

1969年年中至年末,有明确Unix特征的系统就已在运行,可以说那就是Unix诞生的时间了。

unix有什么版本(Unix起源一周)(2)

日期:2003年1月9日,星期四,13:51:56-0800

Unix是用来测试吞吐量之类的文件系统实现。实现出来之后,我发现很难用数据给它加上负载。我可以在循环中调用读/写操作,但做不了更复杂的事。这就是邦妮(Bonnie)去圣迭戈(San Diego)探望我父母时,我面临的状况。

我认为它已经很接近分时系统了,只是还缺少执行调用(exec call)、shell、编辑器和汇编器。(没有编译器)执行调用手到擒来。其他三个每周做一个——加起来正好是邦妮在那边待的时间。

计算机内存有8k×18位。4k做内核,4k供用户程序换入换出。

早期系统有一小群用户,其中当然包括肯和丹尼斯,还有道格·麦基尔罗伊、鲍勃·莫里斯、乔·奥桑纳,以及撞了大运一般的我。每位用户都有一个数字身份编号。有些编号代表系统功能而非人类用户,例如根(root)用户,或者说超级用户,身份编号为0,此外还有一些特殊编号。人类用户的编号从4开始。我记得丹尼斯是5,肯是6,我是9。在初版Unix系统中拥有个位数用户身份编号,大概也算略具声望了。

何以命名

新PDP-7操作系统诞生没多久,就得了一个名字,但具体过程不得其详。

我记得自己站在办公室门口,和几个人讨论,其中好像有肯、丹尼斯和彼得 · 诺伊曼。那时系统还没名字。(如果我记忆准确的话)我提议,从拉丁词根看,Multics意图提供“包罗万象”的功能,而新系统顶多择一而从,应该拿uni来替代multi[3],叫它“UNICS”。

也有人说,UNICS这个名字是彼得·诺伊曼想出来的,代表“毫不复杂的信息与计算服务”(UNiplexed Information and Computing Service)。彼得回忆说:

“我记得很清楚,有天早上,肯过来吃午饭,说他通宵为迈克斯·马修斯(Max Matthews)借他用的PDP-7写了一个数千行代码的单用户操作系统内核。我建议他改为多用户系统,第二天他来吃午饭时,果然已经写出了支持多用户内核的数千行代码。正是那个单用户内核启发了UNICS的‘阉割版Multics’概念。”

彼得自谦地说记不起更多细节,所以,无论是否应当,我都独占了为系统命名的荣耀。

UNICS后来变成了Unix,这名字显然更好。(据传,AT&T的律师们不喜欢Unics这个词,因为它音近eunuchs[4]。)丹尼斯·里奇后来形容这个名字“正中Multics要害”,的确如此。

肯·汤普森小传

2019年5月,在新泽西州沃尔镇举办的美国东部复古电脑节上,我和肯做了一次非正式的“炉边谈话”。我负责提几个问题,然后安坐倾听。以下内容部分来自那次活动,读者可以在YouTube上找到活动视频。

肯生于1943年。他父亲在美国海军服役,肯小时候随军住过全世界很多地方,包括加利福尼亚、路易斯安那,还有几年住在那不勒斯。

他喜欢鼓捣电器,后来去加利福尼亚大学伯克利分校读电子工程。他说,电子学课程确实简单,因为入学之前他已经玩过10年电器。在伯克利分校,他迷上了电子计算。

“我用计算机。我爱计算机。当时,伯克利分校还没开设计算机科学课程,因为这东西刚崭露头角。

“毕业之后那个夏天,我无所事事。能毕业实属惊喜,我都不知道自己居然满足了那些毕业的条件要求。

“我只想待在学校,因为……一切尽在掌握。我手艺纯熟。午夜时分,学校的‘怪兽主机’会关闭。我用自己的钥匙打开机房,启动机器,在次日早上8点之前,它就一直是我的个人计算机。

“我很快乐,毫无雄心壮志,是一个没有目标的工作狂。”

大学最后一年,肯选了埃尔温 · 伯利坎普(Elwyn Berlekamp)的课。伯利坎普当时在伯克利分校任教授,后来不久就去了贝尔实验室。毕业后那个夏天,肯没申请读研,因为他觉得自己还不够优秀。

“到那个夏末,(伯利坎普)说:‘你去读这个研究生班吧。’原来他替我申请了读研,而且申请通过了!”

1966年,肯拿到伯克利分校的硕士学位。贝尔实验室和另外几家公司都想招他,但他明确表态不想去任何一家公司上班。

招聘官一试再试。如肯所言:“贝尔实验室问了6~8次,我都拒绝了——也是因为我没有雄心壮志。贝尔实验室招聘官敲我家门,我请他进屋。据他说,我还用姜饼和啤酒招待了他。”(这大概是加利福尼亚的什么古怪减肥饮食吧。)

最后,肯接受邀请,由贝尔实验室支付旅费,去新泽西看看,但是他只答应去一天,而且主要是为了探访高中时代就结识的朋友。他到达贝尔实验室时,被一些名字打动了:

“一到那儿,我就沿计算科学研究中心的走廊漫步,两边办公室门上写的名字如雷贯耳。太震撼了。面试官是两位妙人……其中一位是林申。

“次日,我租车出行。他们不知怎么查到了我的行踪,还在东海岸我停留的第三站留下一份入职邀请书。我拿了那份邀请书,继续下一站两个小时的行程,边开车边考虑。一到达朋友家,我就打电话去实验室,说我接受邀请。”

肯于1966年加入贝尔实验室,开始做Multics研发工作,后来又写了Unix。这些事前面已谈过,此处不赘述。

肯对游戏的兴趣由来已久。他从小就热爱国际象棋。他不愿输棋,但又会替输了的对手惋惜,所以最终只能做个看客。1971年,他为PDP-11写了一个国际象棋程序。这路子似乎行得通,于是他着手制作用于加速运算(如算出从指定点开始的合规走法)的特殊用途硬件。这些工作累积成了Belle项目(图2-3)。Belle是肯与乔·康登(Joe Condon)从1976年至1980年开发的国际象棋计算机。

unix有什么版本(Unix起源一周)(3)

图2-3 肯·汤普森与乔·康登(计算机历史博物馆供图)

Belle(图2-4)赛绩骄人。在与人类棋手的常规比赛中,斩获2200等级分,成为第一台荣升国际象棋大师的计算机。它还获得了1980年世界计算机国际象棋大赛(World Computer Chess)冠军。在被史密森学会(Smithsonian Institution)收藏之前,它还得过好几次ACM计算机国际象棋锦标赛冠军。

unix有什么版本(Unix起源一周)(4)

图2-4 Belle国际象棋计算机(计算机历史博物馆供图)

丹尼斯·里奇曾经为国际计算机象棋联盟(International Computer Chess Association)写过一篇短文,介绍肯·汤普森对计算机游戏的贡献[5]。文章写道,肯对游戏的广泛兴趣,远远不止国际象棋。文章还写了1978年12月5日Belle在ACM计算机国际象棋锦标赛上击败Blitz 6.5的过程。文中引用计算机围棋先锋蒙蒂·纽伯恩(Monty Newborn)及国际大师戴维·利维(David Levy)的评论:

1.e4 e5 2. Nf3 Nc6 3. Nc3 Nf6 4. Bb5 Nd4 5. Bc4 Bc5 6. Nxe5 Qe7

7.Bxf7 Kf8 8. Ng6 hxg6 9. Bc4 Nxe4 10. O-O Rxh2!! 11. Kxh2 {加速损失} Qh4 12. Kg1 Ng3 13. Qh5 {无效拖延} gxh5 14. fxg3 Nf3# {防住将军,双将且将死,难得一见。“截至目前,计算机程序下出的最妙招数……计算机国际象棋见证了新时代的开始。”}

国际象棋有赢、输或和3种终局。“50步规则”规定,如果在50步棋以内,没有吃子,或者兵没有移动过,则棋手可以提出和局。这条规则能防止玩家在无法赢棋时干耗时间。

肯决定研究50步是否是合适的数字。他使用Belle和一些复杂的数据库组织方式来评估所有4子或5子和局,发现如果采用最佳下法,其中部分棋局可以分出胜负。此时,肯在国际象棋圈已颇有名气,时不时有特级大师来实验室与Belle对弈,尤其是下残棋。我曾经只是因为周末刚好在实验室,就见到了世界冠军阿纳托利·卡尔波夫(Anatoly Karpov)和维希·阿南德(Vishy Anand)。

肯热爱飞行,常常自己或搭载乘客从莫里斯敦机场起飞,在新泽西上空巡航。在他的影响下,1127中心的其他成员也喜欢上了飞行。高峰时期,“1127空军”拥有六七名私人飞行员。他们常常飞去看秋叶,或者到有意思的地方吃午饭。道格·麦基尔罗伊回忆说:

“除了去新英格兰看秋叶,‘1127空军’还去阿迪朗达克山观赏过月食。感谢肯驾驶飞机,罗布·派克提供望远镜。还有一次飞行是去观测水星凌日。Unix组员为天文研究所做的贡献从乔·奥桑纳写的azel[6]开始,这个程序用来控制‘电星一号’(Telstar)的地面站,追踪人造卫星位置。然后是鲍勃 · 莫里斯写的sky程序,还有肯写的天体事件预测器、李·麦克马洪(Lee McMahon)用我的map程序画了星图,最后是罗布写的scat天体目录程序。”

1992年12月,肯和弗雷德·格兰普(Fred Grampp)到莫斯科驾驶一架米格29战机,比他们平时开的赛斯纳飞机更上一层级。图2-5和图2-6展示了肯起飞前和落地滑行的情形。

unix有什么版本(Unix起源一周)(5)

图2-5 肯·汤普森准备起飞(cat-v供图)

unix有什么版本(Unix起源一周)(6)

图2-6 肯·汤普森降落滑行(cat-v供图)

肯和我都于2000年年末从贝尔实验室退休。我去了普林斯顿大学,他加入贝尔实验室同事创办的恩智斐(Entrisphere)公司。2006年,他加入谷歌公司,和罗布·派克及罗伯特·格里塞默(Robert Griesemer)一起发明了Go语言。我听说他离开Entrisphere公司加入谷歌公司,去信询问详情。他回邮件说:

unix有什么版本(Unix起源一周)(7)

日期:2006年11月1日,星期三,16:08:31 -0800

主题:回复:旧时来声

是真的。我没有改变谷歌员工年龄中位数太多,但我想确实拉高了年龄平均线。

本文摘自《UNIX传奇:历史与回忆》

unix有什么版本(Unix起源一周)(8)

《UNIX传奇》[美] 布莱恩·W.克尼汉(Brian,W.,Kernighan) 著

  • UNIX的诞生记与发展史,计算机先驱布莱恩·W.克尼汉继C程序设计语言后又一力作
  • 讲述贝尔实验室的幕后故事,C/C 等重要发明的起源,探寻计算科学之光!

自1969年在贝尔实验室的阁楼上诞生以来,Unix操作系统的发展远远超出其创造者们的想象。它带动了许多创新软件的开发,影响了无数程序员,改变了整个计算机技术的发展轨迹。本书不但书写Unix的历史,而且记录作者的回忆,一探Unix的起源,试图解释什么是Unix,Unix是如何产生的,以及Unix为何如此重要。除此之外,本书以轻松的口吻讲述了一群在贝尔实验室工作的发明天才的有趣往事,本书中每一个故事都是鲜为人知却又值得传播的宝贵资源。本书适合对计算机或相关历史感兴趣的人阅读。读者不需要有太多的专业技术背景,就可以欣赏Unix背后的思想,了解它的重要性。

,