操作系统-操作系统概述
我们目前的计算机都是以冯·诺依曼计算机为模型,主要为控制器、运算器、存储器、输入设备、输出设备,在未来的几十年,随着量子计算机的发展,冯诺依曼模型可能会被打破,那将是计算机领域的一大革新。
程序运行的时候会发生什么?
- 从内存中取出指令
- 对取出的指令进行解码
- 执行指令
如此往复循环,直到执行完程序。
实际上,有一类软件可以让运行程序变得更简单,更方便,甚至可以一次运行多个程序,进行多道程序处理,帮助计算机的使用者管理内存、磁盘等硬件,这类软件叫做操作系统,早期又称为监管程序、主控程序。
操作系统为应用程序提供了很多的API,这些API可以帮助应用程序访问各种硬件资源,这些API称之为系统调用,之所以称之为系统调用,是因为硬件资源是敏感的,不允许普通的用户程序直接访问,只能由操作协同代为访问,因此称之为系统调用。
操作系统的特性
虚拟化CPU
之所以称之为虚拟化CPU,是因为当多道程序在运行的时候,每一个程序感觉自己在独占CPU,使每一个进程产生CPU有无限个的错觉。
但是,每个应用程序还是在单个执行的,至于谁先执行,谁后执行,这个取决于操作系统对进程的调度,也称之为进程的调度算法,我们会在后期进行总结
虚拟化内存
物理内存我们其实可以理解成为一个巨大无比的数组,每次从内存中取数据还是向内存中存储数据,都需要提供索引地址,而在操作系统中,这种访问内存的操作并不允许应用程序私自进行(应用程序也无法私自访问内存),应用程序需要通过操作系统提供的API访问内存,操作系统对真实的物理内存进行了伪装,即为每个应用进程都创建了一个私有的地址空间,让每个进程感觉自己在独占内存。
对物理内存进行抽象,我们称之为地址空间,地址空间就是对物理内存加上了一个映射,这个映射目前来说是不确定的。
使用虚拟化内存的好处在于每个进程都感觉自己有顺序相连的内存空间,并且还可以防止该进程访问其他进程的内存,做到内存隔离
试想一下,我们的计算机当前开着浏览器,然后还开着QQ,如果浏览器可以访问QQ的内存,并且对QQ的内存进行了修改,当QQ得到了CPU的时间片再次运行时,会发生什么,QQ可能会直接崩溃掉了,操作系统不能眼看着浏览器这样胡作非为,也不能允许进程这样
我们希望让许多程序同时运行,所以要确保一个恶意或偶然的不良行为不会损害计算机上的其他程序,也不希望损害到操作系统本身,内存隔离是保护其他软件以及操作系统的基础措施。
并发
其实说到并发,这个概念可大可小,他指的是多个线程之间关于数据安全性的问题,当我们在一个进程中开启多个线程时,由于指令顺序、数据操作的不确定性,就需要引出锁来解决这些问题,引入的锁会阻塞其他线程的执行,因此会带来额外的性能开销。
持久性
在我们使用计算机的时候,数据不可能都存储在DRAM(内存)上,因为RAM一断电所有的数据就会丢失,因此就要把一些经常使用的数据固化到可持久存储的介质上,即机械硬盘(固态硬盘是我们以后研究的方向)或者固态硬盘,但是操作硬盘,如果全靠用户去操作硬盘上的每一个块,这就非常麻烦了,而且文件也不是现在人们想象的那样是一棵树状结构(现在人们的印象都是现在人们所用的操作系统留下的),操作系统就是给了用户一个可视化的文件结构,便于用户增删改查文件,这个软件就叫做文件系统。
向硬盘写入一个文件,就涉及到一些列的系统调用,首先使用系统调用open()打开一个文件,其次使用write()写入文件,最后使用close()关闭文件,告诉操作系统不再写入文件了,其实细化一点,对文件的操作可能会经历一下步骤
- 首先确定所要操作的文件在磁盘上的位置
- 然后在文件系统所维护的各种数据结构中做记录
这里面就涉及到了对各种硬件的底层控制,我们称之为硬件的驱动,如果没有操作系统,每次读写文件都需要人们手动的去操作硬件,工作效率会很低,操作系统为我们操作文件系统了一些列的系统调用,应用层程序员再对这些系统调用进封装,编程普通用户可以操作的图形化界面。
在进行系统调用的时候,并不会立即把我们的写操作执行,可能会延迟一段时间(这也是大多数操作系统的做法),它在等待其他写操作的到来,然后对这些写操作进行分组,提高写操作的效率,为了防止在写的时候发生系统崩溃问题,操作系统还采取了一些手段,例如日志或写时复制,对写操作进行记录,以便在系统崩溃时能够及时的回退(数据库也是采用日志这种机制来对异常进行回退)
抽象
抽象普遍存在于计算机之中,各种设计都体现出来了抽象这高级且不易懂的设计手法,它调高的操作系统的可用性,通过牺牲简单的实现来换取操作的效率,我们上面所说的虚拟机CPU、虚拟化内存、并发、持久性存储都是抽象的体现,这些在我们后续的介绍中都会进行详细的说明,去体验抽象给我们当今工作、生活带来的便利。
当我们使用C语言编写程序的时候,我们不会去考虑汇编,用汇编写代码时,不用去考虑二进制,用二进制构建处理器时不用考虑晶体管。通过这一层一层的抽象,才迎来了我们今天的操作系统
操作系统历史
早期的操作系统
早期的操作系统可以类比为就是一个函数库,在使用的时候可以调用,用此种方式来减少频繁开发的劳动力,类似于今天的java、python等高级的编程语言的封装,内置了一堆的函数库,在使用的时候直接调用就可以拿到结果,例如在Java中,使用链表的时候肯定不会去自己再手动实现链表的逻辑,而是直接使用List即可,早期的操作系统就是这个道理。
当是并不是每一个人都有自己的PC,而是大家共享一台计算机,并且为每个计算机都配备了操作员,大家有任务执行时,将任务交给操作员,操作员将任务分批的放入到计算机中,这种称为批处理系统,另外,任务的执行顺序取决与操作员的心情(类似于今天的进程调度),那时候的计算机还不能与人进行交互,输入的方式也会让当今使用计算机的我们瞠目结舌,采用卡片输入任务,卡片上打点的部分为1,空白的部分为0,通过0、1的顺序进行计算,最后完成任务。
超越库时代
上面介绍了操作系统在早期只是一个库,开发者或者是使用者就是在调用库中的函数,而随着长时间的使用,人们发现了其中的一些缺点,一个程序的内存或者其他数据可能会被另一个程序所读取或修改,这岂不是一点都不安全,这时大佬们就在思考,可不可以在这个库中加入一些特殊的硬件指令以及硬件状态来控制这个权限。于是,超越库时代的操作系统出现了
它主要提供了一个被称之为系统调用的东西,当使用系统调用时(例如读写文件),硬件会陷入到内核模式,此时控制权转移到操作系统(操作系统为内核模式,普通的应用程序为用户模式),因此普通的用户模式无法控制硬件。硬件执行操作系统提前向硬件规定好的处理程序,即操作系统中预定的程序,去打开或者读写文件,操作系统执行完毕后,硬件变为用户模式,操作系统将结果通知给用户程序,将CPU的控制权交给应用程序
操作系统在启动的时候,会向各个硬件通知各种异常(系统调用)的处理程序的位置,当通过系统调用使硬件产生异常,硬件就会去操作系统提前通知好的特定的位置去执行相应的处理程序。我们将操作系统提供的异常处理程序称之为陷阱,硬件产生中断就会陷入陷阱
多道程序时代
多道程序的出现是为了填补之前操作系统的不足,之前的操作系统一次只能处理一个程序,这就会导致当这个程序在进行IO的时候,CPU被阻塞,导致CPU这一个阶段是空闲的,大师们想充分的利用CPU,从而研发出了多道程序处理
多道程序处理一次加载多个应用程序,并且在这些程序之间迅速循环执行,这就带来了一个问题,如果一个程序修改了另一个程序的内存,将会带来什么样的后果?这可能是无法想象的。
内存保护这个时候尤为重要,对每个进程的内存信息进行保护,防止其他进程进行修改。
在当时,搭载着多道程序处理的操作系统unix问世了,这是贝尔实验室对世界作出的一大贡献。
增强时代
PC的出现可以说是现代计算机的一次科技与技术的革新,由传统的多人一台计算机到每个人桌面上一台,这是一种翻天覆地的变化。
但是在个人PC诞生之初,人们忘记了内存隔离的重要性,许多应用程序将内存修改的乱七八糟的,导致程序运行着就崩溃了,好在这种情况出现的时间不是很长。
unix在70、80年代的传播速度异常的惊人,但是在后期,由于各种经济利益纠纷,很多人开始远离unix,在90年代初,一个荷兰的黑客基于unix的设计思想研发出来了Linux,并且取得了巨大的成功,截止到目前也可以验证这种成功,现在的Linux被使用在各个发行版,例如Redhat、debain、fedora等
乔布斯将他的基于Unix和NeXStep的操作系统带到了苹果,成为了目前程序员(me)最想得到的主力机。
总结
我们从冯诺依曼计算机体系开始,介绍了计算机执行程序的流程,然后引出了操作系统的概念,又从虚拟机CPU、虚拟化内存、并发以及持久性方面对操作系统进行了一个简单的概述,最后介绍了操作系统的历史发展
下一篇会对虚拟化CPU开始进行一个总结
make it better