【操作系统】chapters0_重识操作系统

重新认识操作系统

文章一共 10981 个文字,阅读时间约 10 分钟左右。

第一、第二均属于扯淡范围,如果不是很感兴趣的话可以直接跳过。

一. 操作系统初定义

操作系统 这个词语,在接触电脑的第一时间开始,就可以开始听到了。依稀记得那年 2008 年家里新购的一台某想的电脑,路边电脑铺大哥就给我安了一个叫 “Windows Vista” 的操作系统,并且跟我说这个是目前最新版本的系统了。但,我这个系统怎么看起来没有毛玻璃,没有半透明,没有酷炫的 3D 任务画面切换功能,且 我的电脑 属性显示的是 Windows XP 咧 。就这么带着疑惑使用了大半年,由于经常上能够让人气血澎湃的网站,所以经常深度中毒了。

Windows Vista的任务预览图

一不做二不休,总是叫人家电脑铺老板过来也不太好意思,就自己百度了怎么重装操作系统。那时候风靡一时的有什么 雨林木风 深度 网上的评论都很不错,偶然看到我朋友提起那个熟悉的名词 Windows Vista,那就下一个看看,由于不会装 驱动(我是S*),所以显示器来有点奇怪,一点都不如 Windows XP 好用,还一卡一卡的。所以也用了蛮久的 Windows XP 了。也不知道什么时候突然顿醒了了,知道了还有驱动这个事情,于是下了当时最新的系统 Windows7。草(一种植物),之前 XP 下根本没法玩的 生化危机4 居然流畅的跑起来了,而且还有一堆其他游戏也跑起来了,然后一顿赞美以后。就读大学去了。

聊了这么多的故事,操作系统 我只认识到,这是一个可以让一个箱子里面的零固件发生一系列很微妙的转换,并且还可以看着显示器,做很多事情的东西(现在看来应该说软件,但是那时候只知道一台电脑,就需要 硬件+操作系统 才可以开始正常使用)比如说:玩游戏啦,看电影啦,看视频啦,学习一些 “技术”啦等等。如果说买了一台电脑,没有安装任何的 操作系统,那这台电脑,就是不好玩的。

哦,对了,那时候还有另外一个兴趣就是,看着诺基亚手机论坛一个一个发布的 ROM,恨不得每一个都刷一次,所以我每天基本打开电脑就是在刷手机,后面也遇到了在 5530 型号上的手机运行 C6 ROM 的事实,好生好奇,不过知识浅表,知道可以这么玩就是了。

二. 历史发展

带着 一台电脑,必须拥有对应的操作系统才能正常运行 的想法,来看一下 操作系统 在几个时期下的状态。

第一台真正的数字计算机,来源于英国数学家 Charles Babbage,他从法国人杰卡德发明的提花织布机上获得了灵感,制造了一台小型计算机,能进行8位数的某些数学运算。而后,英国政府觉得有利可图,遂资助大量资金给 Charles Babbage 研究第二代大型差分机,但这台差分机难产了。再然后 Ada 加入了他的团队,他提出了更加跳跃的想法,这台机器能够自动解算有100个变量的复杂算题,每个数可达25位,速度可达每秒钟运算一次。Ada 则扛起了对这台机器编写程序(指的是通过物品编写程序)的重任,而她发现这些程序的编写跟织布机的某种零件一样。所以她成为世界上第一个程序员,也是发明了函数的人。

自第一台计算机被提出设计出来以后,第二代差分机虽然难产,但是设计等方面却流传了下来,这时候熟悉的第二次世界大战开始了。由于战争的需要,催生了第一代计算机的诞生。

第一代计算机 没有设计语言,也没有操作系统,程序使用的是机器码编程,介质是插件板。使用方式是将编写好的程序插件板插入到计算机里,几个小时后就可以计算出结果出来,这一代计算机一般用于一些简单的数学计算,可以说现代我们使用的计算器,比第一代计算机的功能还要强很多。后期出现了穿孔卡片,但是编程依然需要使用机器码在卡片上编程。

第二代计算机 开始发展了,计算机厂商已经可以量产计算机出售,但是价格十分昂贵,只有学校或者政府才有可能购买使用。第二代计算机使用磁带保存运行时数据,通常程序员使用 Fortran语言或汇编语言 编写程序,穿孔成卡片,然后将卡片带到计算机室(Emm 以前的计算机占地面积比较大),稍等计算机工作人员运行程序并拿到程序的结果(一般打印在纸上)。而把镜头转向操作员这边来,操作员需要接收到一个卡片,如果需要 Fortran编译器 的话还需要装载编译器读入计算机,然后再把程序结果递交给程序员,然后去接收第二个任务重复上面的动作。由于这种工作方式导致很多时间浪费掉在走路,沟通,装载程序上面,所以操作员一般会汇集很多个任务才开始进行计算机的操作,并且使用价格比较低廉的计算机进行程序的读取以及结果的打印,而价格比较昂贵的计算机则用来做程序的运算,这种方式也称为 批处理作业

批处理作业 流程一般就是操作员先聚集一批作业,放入读卡机,输出到磁带,然后将一个程序(这个程序可以看做 操作系统 的前身)装载到负责计算的计算机上,这个软件即可在计算机完成一个任务以后自动读取下一个任务,将结果批量的写到输出磁带上,然后操作员再把这些磁带拿到打印机进行批量打印。

第三代计算机 的形态就跟现在的计算机形态很相像了, 在 第二代计算机 时代中,我们知道了低端的计算机用来输入和输出打印,高端的计算机用来运行程序。但是这个情况导致了面对需求的变化十分无力(是的,需求!)。许多用户本来只需要一台低端的计算机,但是后期需求变得宽广了就需要一台高端的计算机,而这两款计算的运行方式是不互通的。所以著名的 IBM公司 发明了 System/360 来视图解决这个问题,360 是第一个采用芯片(集成电路)的主流机型,与上一代计算机相比,性价比有很大的优势。但是 IBM公司 又由于需要将这套程序做成能够兼容打印,大型计算等领域,将 OS/360 开发成一个怪兽(即包含着数百万行汇编代码),补丁打了又打,旧的错误解决又引入新的错误(我们现在的日常),导致这套系统非常庞大。

但是 OS/360 很多功能都是有意义的,最重要的功能是能够支持多道程序设计,由于大部分程序均有 IO处理,而大型商业软件的 IO处理 更是高达 80%**,所以这套系统支持在内存中驻留多道程序,当 **A程序 需要等待 IO处理 时,CPU 便可转而去处理 B程序CPU利用率 高达 **100%**。另外一个重要的特性是,支持快捷的输入输出功能。上一代计算机需要人工的进行磁盘的装载,但是这一代的计算机可以通过外部设备联机操作,快速的输入和输出信息。

虽然说上面描述的操作系统已经支持多道程序,但是由于本质上还是 批处理作业,所以导致多个程序执行的时候,还是需要等待很长的时间。所以,分时系统 诞生了。第一个 分时系统 是由 MIT 开发而成的。而 分时系统 诞生以后,MIT贝尔实验室 以及 通用公司 决定开发一套可以同时支撑数百个用户计算需求的系统,这套系统名为 MULTICS,他需要运行在一台计算机上(性能嘛,需要感受一下),就能够支撑数百名用户,显然在当时那个情况下是不太可能的。但是他跟世界上 第一代计算机 一样,散播了很多原创思想。到目前来说,至少支持多人计算服务这个事情已经被实现了,即 Web服务,在远程的服务器上运行着需要大量计算的软件,而我们个人计算机只需要在 Web页面 上简单的输入我们的请求,即可实现计算。

一位参加过 MULTICS 研制的科学家,对 MULTICS 进行了改版,开发了简化版的 MULTICS,这导致了 UNIX 系统的诞生。而由于 UNIX 系统是开源的,所以导致各个机构开发出了不相互兼容的版本。为了使软件能够兼容各个版本的 UNIXIEEE 甚至还提出了 UNIX 的标准:POSIX

接下来的事情大家就比较熟悉了,1987年的时候,一位大学教授编写了一套操作系统 MINIX3,该系统只应用于教学目的,而他的学生 Linux 则编写了系统 Linux,目前成为世界上用户量最多的服务器操作系统。

第四代计算机,也就是现代时代了,比尔盖茨 乔布斯 的时代。这时候操作系统从简单的 DOS接收用户输入并输出结果 的时代,转而拥有 GUI 可以通过鼠标窗口来输入数据的时代。所以我们现在的争论也是某某系统的更加好用,其实讨论的不都是哪个系统的 GUI 比较好用。

三. 硬件搭配

进入正轨,在讨论 操作系统 这个软件之前,我们需要先观察一下硬件方面的事情。一台简单的现代计算机,基本上都需要具备以下几个要点:CPU内存 以及 IO设备

现代计算机零部件

3.1 CPU

毋庸置疑,一个标准的计算机,他为什么能计算,原因在于他有一颗能够计算的大脑:CPUCPU 日常需要处理的事情无非就是:1. 解析指令;2. 执行指令;3. 保存结果。当然由于 CPU 的计算能力要比 从内存中取出指令或数据 要强得多(这也算是 IO处理 了)。所以,现代的 CPU 通常拥有缓存最近的存取数据的位置(速度不够,缓存来凑),那就是 寄存器

3.1.1 寄存器

寄存器 通常拥有几种类型:

  1. 用于保存变量和临时结果的 通用寄存器,该寄存器通常用来将数据从内存中读取,并且将执行结果写入内存;
  2. 用来保存程序执行位置的 程序计数器,用于记录程序需要执行的下一条指令的内存地址,当计数器中的内存地址被取出正在执行以后,程序计数器 将会立刻收集下一条指令的地址;
  3. 保存函数执行状态的 堆栈寄存器,保存当前函数执行的局部变量以及有关的参数输入;
  4. 包含条件码位、CPU优先级、模式(用户态或者内核态)以及其他控制位的 程序状态字寄存器(Program Status Word,PSW)

计算机怎么给人一种有多个程序同时运气的错觉,就是因为每一个程序分配了很多的时间片进行执行,在一定的时间范围内,CPU 会将程序的状态立马保存起来(通过寄存器与内存沟通),然后执行另外一道程序(重新加载另外一道程序的所有状态)。由于切换时间很短,在人眼的可识别范围以外,所以可以给人一种有多道程序同时运行的错觉。

当然,喜欢折腾的 CPU工程师 为了提高 CPU 的执行效率,现代的 CPU 具备了同时去除多条指令的机制,以便让 CPU 中的 取指单元解码单元执行单元 不会被空闲着。指令所需要经历过的单元顺序跟上面的描述顺序一致。

更是然后,出现了 超标量CPU,他放置了更多的 取指单元解码单元,一次性读取多条指令,甚至出现多个 执行单元(跟多核心有区别,执行单元可以将整数、浮点数、布尔值的计算分开),从而可以更快的完成程序指令。这就导致一个后果,我们编写的指令通常不按顺序执行,如果稍微不注意,就很容易出现结果与预期不同的问题(高情商解释)。

3.1.2 内核态和用户态

内核态和用户态的出现,最根本的原因就是保证硬件使用的安全性(指的是计算机运行的安全性)。在 内核态 的状态下,一般只有 操作系统 这套软件可以使用,它具备访问整台机器连接设备的权限,包括调整磁盘读取的指针啦,内存数据的清理和写入啦等等方面。而用户程序大多运行在 用户态用户态 大体并不需要去操作外部的设备,比方说 用户态 读取计算机时钟,就可以直接在 用户态 下执行。

所以说,内核态 可以说拥有 CPU 整个指令集的执行权,但是 用户态 却只能执行 CPU 整个指令集的子集,一般是没有损害硬件的指令。

但不管怎么说,用户态 的程序很多时候需要操作 硬盘网络 或者 内存 等硬件。这时候就需要切换程序运行的状态了,将所需要调用的功能提交给 操作系统 去执行。此时必须使用 系统调用 将状态陷入 内核态,用的是 TRAP指令内核态 操作完成以后再把 数据 传递给 用户态 的程序,并且将当前状态切换回去。

3.1.3 多线程CPU和多核芯片

随着 CPU 开发工业的逐渐精湛,CPU 也需要更多的承担更大的计算量才行。牙膏厂就使用了一项技术:多(超)线程CPU。他设计 CPU 核心的时候,允许他同时保持两个不同的线程状态,以纳秒级别的速度进行切换。对外开放给 上层系统 时,开放两个 CPU 的权限。所以在单核双线程的 CPU 上,上层系统 可以当成两个核心来进行操作使用。

而现在,我们当然可以看到有多个核心的 CPU,此时 取指单元解码单元执行单元 就不止多出一倍出来,可以同时执行更多的计算量。

但是也有 缓存 方面的顾虑,缓存可以有两种解决方案,一个是每个芯片都有自己的缓存体系,另外一个是多个芯片共享同一个缓存体系。当然各有各的优缺点,各自拥有缓存体系在保持一致性的时候带来困难,而共享同一个缓存体系的话,则会带来数据写入时需要争夺的问题。AMD 用的是前者的方案,而 婴特儿 用的是后者的方案。

3.2 内存存储器

CPU计算机 的大脑,负责运算。但是这时候还需要一些临时的零件来存储大脑计算时所需要的数据以及指令。那就是 内存存储器

内存存储器 分为好几个等级,简单的介绍一下有:寄存器高速缓存内存 以及 磁盘。其执行速度自左到右,而存储的容量则反过来。

3.2.1 寄存器

这个设备在 CPU 章节中已经做过介绍,由于他所使用的材质与 CPU 一致,所以速度也跟 CPU 一样快。但是由于价格高昂,所以存储容量也非常小。典型的 32位是323264位是6464。无论哪一种 CPU 其存储容量均小于 1kb

3.2.2 高速缓存

目前市面上很多的 CPU 具有三级缓存,分别记为 L1(kb级别)L2(mb级别) 以及 L3(mb级别)。高级缓存大部分放置于 CPU 内部,或者靠近 CPU 位置的外部主板上。每一级的速度逐渐递减。多数操作系统会将需要频繁使用的文件(或者一部分)放置于 高速缓存 中以避免频繁的读取。

3.2.3 主存(也就是内存条)

这里存储的数据就要大得多了,在 2020年8gb内存 的计算机都已经很难满足一些常规的需求了。所以这里是程序数据存储的 主力。通常称之为 RAM(Random Access Memory)。而且这里如果断电就会损失数据。而部分比较小型的计算机(比如说计算器),会内置不损失数据的内存,用来保存一些小程序,称为 ROM(Read Only Memory),他即使断电也不会造成数据的丢失,一旦开启电源,就加载程序到 RAM 中用于运行,比方说:洗衣机的程序、一些智能设备包括手机呀等等。

另外还有一个存储数据的地方就是 EEPROM(Electrically Erasable ROM,电可擦除可编程ROM),他没电就丢数据,像电脑的主板,有一颗小电池长期供应着这块内存的电,所以电脑才可以记录 BIOS 的设置以及时钟的数据。如果电脑用了很长一段时间,这可电池没电了,那么将会导致每次进入系统都没记住先启动哪个盘,也没记住时间,都需要重新设定。

3.3 硬盘

硬盘是具有比 主存 更大容量的数据存储零件,而且相比于 内存 而言,他的价格要便宜很多,而且断开电源不会造成文件的丢失。现在常见的 硬盘 也分为 机械硬盘固态硬盘

3.3.1 机械硬盘

这个应该不陌生,现在还有很多电脑在使用 机械硬盘 存储大量的数据,因为在接下来要说的 固态硬盘 他的访问写入速度虽然快,但是价格还是比较昂贵的,所以当有需要大量的文件需要存储的时候,还是会选择 机械硬盘

机械硬盘为什么访问会比较慢,原因是由于他的数据记录在一张圆形的,类似于光盘的金属盘片上。当机械硬盘开始运行的时候,这个盘会转,然后通过 磁头 读取数据。所以当我们所需要随机访问一篇数据的时候,操作系统 需要确定这块数据在哪一块 扇区 上,传送变量给 硬盘的设备控制器,然后移动 磁臂 以便带动 磁头 到达那个位置,到达了以后,就需要等待 金属盘 转到 磁头 的位置(所以机械硬盘有个参数是转速),然后开始读取数据。

3.3.2 固态硬盘

由于 机械硬盘 的发展已经出现了瓶颈,当人们需要更高的访问速度的时候,研究出来了 固态硬盘。简单了解一下 固态硬盘 的原理即是,在一块电路板上,使用一些介质表示 01 来存储数据,其原理来源于 内存,当接收到读取或者写入的时候,由 设备控制器 直接决定要对哪些部位的 介质 进行操作,从而返回数据。

当然,固态硬盘 的缺点就是,介质 的读写次数是有限的,当超过次数的时候,这一个部位的 介质 就无法使用了。所以我们使用电脑的习惯也需要发生一些改变。比方说不要进行碎片整理。

3.4 IO设备

I/O操作 是开发者在开发软件的时候经常遇到的问题了,而软件更多的时候考虑,怎样在进行 I/O操作 的时候,做更多的事情,或者用哪些方式比方说压缩数据啦来加快 I/O操作 的速度。典型的 IO设备 有:硬盘网卡。前者管着数据的存储,后者管着数据的发送。

但是到了 操作系统硬件 的时候却不是考虑这些东西。

3.4.1 组成和控制

首先,需要了解 IO设备 是怎样组成的。IO设备 通常具有 设备控制器设备本身设备控制器 通常是一个微型的操作系统,它用来接收通过连接线接收到的指令,并且翻译成 IO设备 所能理解的 电容信号,比方说一个 硬盘,连接线传递来了需要读取哪里到哪里的数据,设备控制器 则需要移动 磁臂 并且确定需要读取的区域,然后读取数据,再 返回设备控制器 翻译成标准协议所能理解的数据输出到 操作系统

3.4.2 操作系统兼容

那现在手上有一块 IO设备,他插入到计算机,怎么去理解 IO设备 所能做的事情呢。这时候就需要 设备驱动程序操作系统 需要用到对应的 IO设备 的时候,就会寻找对应的 设备驱动程序,传递指令,此时再由 设备驱动程序 寻找 IO设备 连接的 端口 将数据或指令 传送 给设备管理器。

安装 设备驱动程序 一般有几种方式:

  1. 内核与 设备驱动程序 重新连接,手动重启系统,让操作系统读取;
  2. 通知系统需要加载某个 设备驱动程序,操作系统重启时把此 驱动 加载到内存中去;
  3. 即插即用,动态装载设备驱动程序,现在大部分使用的都是这种方式。

3.4.3 调用硬件功能

有两种方式可以进行调用:

  1. 设备寄存器被映射到操作系统的地址空间,然后我们操作的时候只需要像日常操作一样对该地址进行操作即可,Linux一切皆文件 使用的就是这种方式;
  2. 使用专门的指令,设备寄存器被连接到主板上的端口,需要操作的时候,软件将对特定的端口发出指令进行操作。

前者占用了一些操作系统的地址空间但是不需要特定的指令,后者则完全想反过来。

然后就需要对 IO设备 进行调用操作了,主要有以下两种方式:

  1. 程序发出一个系统调用,系统调用再根据设备驱动发出一个过程调用,然后 CPU 不断的循环问这个设备,你做好了吗,当 IO设备 完成操作以后,返回给 操作系统,再返回给 用户程序。这种方式不用说也明白,浪费 CPU时间
  2. 程序发出一个系统调用,操作系统再发出一个过程调用,此时,操作系统 将会 阻塞用户的进程,当设备完成工作的时候,将会 通知 操作系统(操作系统 也可以暂时不接收),从而读取设备返回的数据再返回给 用户程序
  3. 引入 DMA芯片 来完成 第2种方式 中的任务。

3.4 总线

由于需要连接的东西越来越多,所以总不能通过简单的连接方式进行。总线 就诞生了。主要就是我们看到的 主板。拆过计算机的就知道,CPU 安在了主板的中间,而主板上会拓展出来各种各样的接口,这些电路板所形成的连接线路,就是总线。当然,分出来的有各种各样的总线:IDE总线图形适配器总线USB总线 等等。所以有了总线,就需要总线的 设备管理器操作系统 才可以灵活的调用每个部分从而操作各个 IO设备

3.5 计算机启动

当按下计算机按钮的那一瞬间,位于主板上的 ROM 将被启动,这个 ROM 装载着 基本输入输出系统(Basic Input Output System,BIOS)。他将检测主板上连接的基础设备(通常是 CPU内存 以及 硬盘),如果这几个东西有某一样不正常的,将无法正常进入系统。然后,主板将从 CMOS 中读取我们之前的设置,比方说开机从哪个硬盘开始启动,时钟等等。如果 操作系统 安装正常的话,那么 BIOS 将从硬盘中读取出活动分区,然后从该分区中加载启动模块(通常这个启动模块将会启动整个操作系统),然后 操作系统 将会从 BIOS 中读取出设备信息,并且将 设备驱动程序 加载到内核中,初始化对应的背景进程,从而启动对应的 GUI 或者 终端

四. 重识操作系统概念

上面说了这么多硬件方面的问题,很多硬件的运行都需要来自 操作系统 的调度。所以再不可简单的认为,操作系统 就是什么 macOS 啊,Windows 这些简单的概念了。

所以说,可以协调 硬件 工作并且达到计算目的的软件,即为 操作系统。无论小到 洗衣机 上面的控制程序,还是 手机 上的 可以运行软件的软件,最后到 电脑上 的系统,均可视为 操作系统。并且,操作系统 还肩负着一项重要的任务:协调各个程序的运行,提供调用 硬件设备 的能力,有条不紊的调用连接的 设备,从而完成一系列计算任务。

五. 操作系统抽象的概念(内核功能)

OK,既然一台完整的计算机,必定拥有很多连接的设备,所以如果没有操作系统来抽象这些硬件,那么将导致我们在为 计算机 开发软件的时候,总是需要考虑从哪里读取数据,怎么调用硬件的问题(不管怎么说,每一种设备的协议的调用方式都是又臭又长的)。所以,研究计算机的老头们,为了能够更加完整的榨干硬件最后一滴血,开发出了 操作系统 这套软件。

所以我们在开发软件的时候,我们的软件其实是运行在 操作系统 这一个容器里边的,当需要对外部设备进行操作的时候,软件将灵活的调用各自操作系统抽象出来的 API接口,传递调用数据以及函数给到 系统系统 将会安排一些时间以便调用 硬件 来获取对应的数据,而 设备 运行的效率基本都要比 CPU 慢好几个数量级,所以,操作系统 在这段空闲的时间,又可以安排其他软件进行运行。

那么,抽象出来的产物就有:进程、地址空间、文件、输入/输出、数据权限以及 shell

5.1 进程(process)

操作系统 是用来运行 程序 的,而这些 程序 启动以后,就会变成一个一个的 进程 运行在 操作系统 中。所以 进程 指的是 运行中的程序。而 进程 运行时,将会在 内存 中放置运行所需要的数据,这将是下一个概念,地址空间。地址空间包含着程序运行时需要的所有数据的地址,一般从小到大有一个 地址列表,存放需要执行程序的代码、数据、使用的整个堆栈,还包含着寄存器记录的数据(程序计数器和堆栈指针),打开的文件列表,错误报警以及其他的清单。

在一个支持分时处理的 操作系统 中,为 进程 分配时间片进行运行时就需要频繁的与 地址空间 进行数据交换。考虑通常我们一边在下载东西一边在上网,我们通常需要两个进程,一个下载器的进程,另外一个浏览器的进程,而系统将会在下载器进程运行一段时间以后将下载器挂起,从而转换到浏览器进程处理,然后再将浏览器挂起再切换到下载器进程上来。考虑到进程从活动中到挂起这一步,在还原的时候就需要还原到原来挂起的模样,所以就需要把 CPU寄存器 中的数据交换到 地址空间 中,然后还原另外一个进程的 地址空间数据寄存器 中进行运行。

而通常 进程 是可以启动另外一个 进程 或者对另外一个 进程 发出命令的,比方说我们通过 shell 启动了 mvn 程序对代码进行编译,而中途由于某些原因我们需要退出,于是我们按下 CTRL + C,那么 shell 这个进程将会对 操作系统 发出指令说要停止 mvn 程序,操作系统 可以模拟一个警告信号给 mvn 程序以便让程序挂起,挂起完以后便可结束 程序

5.2 地址空间(address space)

上面说到,软件运行时候很难避免需要数据交互到内存中来,所以就需要 地址空间 来表示 内存 中数据的位置范围。在支持分时系统的 操作系统 中,内存中通常存放有很多 进程 的数据,有必要保护每一个 进程 的地址空间,以防被其他恶意的程序破坏导致软件运行异常。

地址空间 还可以指向 虚拟内存操作系统 可以利用 硬盘 的空间来存储运行时的数据,所有这些地址将被一起整合为 地址空间 以便提供给软件进行使用。

5.4 文件(file)

文件的概念包含了 数据文件 以及 目录。当我们的程序需要对 硬盘 上的数据执行命令的时候,都需要通过 系统调用,指挥 操作系统 来定位 磁盘 的地址位置,从而实现文件的增删查改。

通常,文件的地址均以根目录开头,表示 /**(就不讨论 **Windows 了),然后一层一层的定位到具体的文件或目录中去。在对文件进行操作之前,操作系统 都需要先 打开文件,然后检查用户的访问权限,再决定是否进行下一步的操作。

UNIX 系统中还有另外一个重要的概念,就是 一切皆文件。所以我们可以将外部 IO设备 挂载到一个指定的文件中,然后我们使用 文件操作命令 来对这些 IO设备 进行一系列的操作。对文件的操作指令将会被 操作系统 翻译成具体的设备信号发送给 IO设备

而另外一个重要的概念是 管道。当我们需要启动两个进程相互交换数据的时候,就可以使用 | 这个字符来表示管道,管道 是另外一种特殊的 文件,他表示第一个进程将结果写入管道,第二个进程从管道中读取数据进行运行。比如:ps -ef | grep java

5.5 输入/输出

典型的 UNIX 系统就是将所有的 设备 抽象成 文件 的形式进行输入与输出,这个可以直接使用 文件 这个概念来描述。

5.6 数据权限

上面的概念都需要与硬件交互,而这一个功能,则是对数据的保护了。UNIX 系统我们知道有三个权限:可读可写可执行。并且使用三组来表示,比方说 rwxr-x–x ,分为三组,第一组表示用户的所有者,第二组表示跟用户同组的其他用户,第三组表示其他用户(当然不包含在第二组的范围内)。r 表示 可读w 表示可写,x 表示可执行,**-** 表示没有设置,也可以理解为 的意思。

5.7 shell

这个很熟悉了,这是我们命令 操作系统 干活的入口,很多时候我们都不需要特别的 GUI 来协助工作,只需要在 shell 中键入命令,命令将会解释成 操作系统 的指令,然后调用上面各个部分的内容来完成我们的命令。这个并不属于 操作系统 的范畴,但是是使用 操作系统 最基本的入口。shell 中所输入的命令,将会启动一个子进程进行运行,窗口将会停留在进程中等待进程结束,当然如果我们想要进程后台进行的话,可以在命令的后面加上 & 表示后台运行即可,但是进程的输出数据依然会打印到我们的 shell 中。

六. 系统调用

由于上面所说的 操作系统 提供的抽象,所以无论我们的程序需要对特定的硬件做任何事情,都需要经过 操作系统,也就是 内核 的调用,使用的是 内核 抽象出来的函数调用。

比方说现在程序需要从硬盘中读取一段数据,那么他需要下面几个步骤:

  1. 通过类库调用 read 函数,操作系统 会将参数以及 read 的代码放入 寄存器 中;
  2. 程序执行一个 TRAP 指令,将当前系统所在的 用户态 切换到 内核态
  3. 操作系统 将根据 read 去查找对应的调用编号,发出调用命令,发出指令以后,阻塞用户程序,然后这时候 操作系统 可以安排另外不需要阻塞的进程继续运行;
  4. 硬盘 开始进行读取,读取完成以后,将数据以及跳转的位置返回给 操作系统,然后 操作系统 再将结果返回给用户程序调用的位置,继续程序下一步的操作。

而每一种 操作系统系统调用 也完全不一样的,所以还需要根据不同的 操作系统 来编写不同的程序。比方说创建一个线程,UNIX 用的函数是 forkWin32 用的函数是 CreateProcess

七. 操作系统结构

这个结构就很像 JavaWeb 程序的演变过程啦(所以其实只是使用的语言不同但是思想却总是那么几个)

7.1 单体系统

这个理解就很简单了,把 操作系统 所具备的所有功能都放在同一个项目当中,整个 操作系统 以过程集合的方式进行编写,每一个 过程调用 均可以方便的调用到其他的 过程调用

7.2 层次性系统

这个就是根据不同的需求进行分层了,一共分为六层,每一个低层都为高层提供服务:

层号 功能
5 操作员
4 用户程序
3 输入/输出管理
2 操作员-进程通信
1 存储器管理
0 处理器分配进程

这样编写程序的时候大体发生在第 4 层,那我们就可以通过第 3 层的输入与输出来调用 操作系统 了。

7.3 微内核

由于上面两种方式都是单体架构的方式,所以很容易其中某个模块出现问题的时候,引起整个 操作系统 的崩溃。所以提出了 微内核 的做法,微内核 指的是只有 操作系统内核 运行在 内核态 上,而其他的注入设备驱动程序则运行在 用户态 中,这样某个设备驱动程序出现了错误,才不至于导致整个操作系统的崩溃。而这些设备驱动程序则作为用户程序服务器,接收高层用户程序运行时所执行的请求,比方说有 FileSystemProcess 等服务器。熟悉的 MINIX3UNIX 类系统采用这种方式进行编写。

当然,Linux 则汲取了 微内核 的精华,具体原因是 微内核 的设计由于设备驱动程序位于 用户态,进行调用的时候需要通过 系统调用 来切换 内核态 会导致性能上有所损失。而 Linux 则作为一个单内核,提供了 模块化设计抢占式内核支持内核线程 以及 动态装卸内核模块 的能力,直接使用函数调用。

7.4 客户机-服务器模式

哎呀这种模式就很熟悉了,当我们需求是一个随时可以访问的文件系统的时候,就可以使用这种方式来部署我们的项目,比方说部署一个网络云盘。然后我们就可以在所有拥有连接网络的计算机上随时访问我们的文件目录了。

7.5 虚拟机

目前看到的虚拟机分为几种类型:直接在物理机上实现虚拟机,在当前用户操作系统上实现虚拟机。

前者,我们需要安装一个虚拟机管理软件系统到我们的实际物理机上,然后这个软件就可以分隔开的运行不同的操作系统,来提供不同的服务。而后者我们就很熟悉了,著名的软件有 VMware Parallels Desktop 等软件,这种方式,宿主机可以正常运行用户的程序,而虚拟机内部虚拟出来的系统,则可以运行特定环境下的软件,如:调试安卓软件时所需要的系统。

而运行虚拟机软件(指的是 VMware 这一类虚拟机软件)一个重要的环节就是,当前的硬件 CPU 允许用户态的软件运行特权指令(因为虚拟机中的系统通常需要运行一些IO指令等情况),如果不允许的话,那么这些特权指令将被无视掉,也就造成了当前的机器无法运行虚拟机软件的必要因素。

还有一款虚拟机就特别常见了,比如 JVM虚拟机 或者 GO虚拟机,它允许 Java 代码生成的字节码在上面进行运行,这就提供了我们熟悉的 class 文件在网络上传播并且加载到客户端的虚拟机上进行运行的可能。

7.6 外核

通过虚拟机可以虚拟不同的系统,但是有没有发现一个问题,就是资源的分配。所以衍生出另外一种模式,外核。我们可以使用 外核 运行在实际的机器上,并且分配不同的资源给到不同的虚拟机,比方说:虚拟机1 只能访问硬盘的 0-1023 范围内的资源。

当然如果没有外核,虚拟机软件也可以实现这个功能,但是就需要使用内存中保存的表格来进行监控,额外的增加了运行的成本。

八. 小结

  • 聊了聊与电脑相识的故事,唠嗑一下计算机发展的历史;
  • 认识一些基础的计算机硬件;
  • 了解了操作系统是如何管理和抽象计算机硬件的;
  • 操作系统的元素和构成;
  • 虚拟机的认识。