1.1.定义
如果我们直接将计算机的硬件组装在一起后就拿来使用,至少会有以下几大问题:
- 不友好
- 不安全
- 效率低
不友好:
硬件操作是十分复杂的,如果对计算机的操作都是直面硬件,对于操作者(用户或者应用软件)而言将会十分不友好。
不安全:
如果对计算机的操作都是直面硬件的,恶意应用软件对计算机的攻击会很容易。
效率低:
由于缺乏对于任务的调度管理,首先,指令的执行将会变得不可控。无法知晓指令何时执行完毕,高优先级的指令可能无法被率先执行。其次,资源的利用率将会很低。因为无法对指令的执行进行干预,当前指令执行所涉及的资源之外的资源将会被直接闲置浪费掉。
综上所述,在硬件和用户之间需要一个中间层,这就是操作系统。操作系统(operation system,简称OS),是位于硬件和用户之间的中间层软件。面向用户提供用户接口,方便用户控制计算机,面向计算机,在硬件层上提供一套资源调度策略,负责完成资源调度管理。
需要调度的资源也就是外设资源(外姐设备、外存)、内设资源(CPU、内存),因此操作系统可以简单的理解为给用户提供各种对计算机的管理功能的一个软件。 这个管理软件有四大功能:
进程管理:
进程管理,即CPU管理,CPU内置的运算器、控制器,只会单纯的去完成自己的工作,在没有合理的调度算法的控制下,只会傻傻的串行执行,操作系统则提供合理的调度算法,让CPU的资源被合理利用,从而使得进程可以被并发的执行。
内存管理:
设备管理:
操作系统负责进行设备的分配和调度。多个进程争抢单个设备资源的时候(如争抢打印机),操作系统会进行合理的调度,谁先使用,谁后使用。
文件管理:
操作系统负责对硬盘资源进行调度管理,如新建文件夹,将文件放到文件夹中,删除文件夹,删除文件。
其实一个软件实现对CPU和内存的调度管理,即进程管理和内存管理,理论上就可以被认为是一个操作系统,因为已经实现对计算机核心部件的管理,可以完成核心功能的调度,但是现代操作系统为了方便使用,因此多是实现了对外设资源的管理。
1.2.发展史
整个操作系统的发展史分为四个阶段:
- 手动
- 单道批处理
- 多道批处理
- 分时系统
手工阶段:
就是手动来操作系统一条指令一条指令手动的往主机里送。
单道批处理:
管理员事先将多个作业输入队列形成作业队列,操作系统依次串行自动处理队列中的每个作业,运行完毕后通知用户取出结果。
因为是串行处理,程序执行时会独占CPU,当独占CPU资源的当前进程在使用外设资源,而不是使用CPU内部的运算器的时候,CPU实际上处于空闲状态,造成了CPU资源的浪费。
多道批处理:
在内存中存放多道程序,当某道程序因为某种原因放弃CPU资源时,其他程序可以马上补位,继续使用CPU。
运行过程不确定,被其他程序钻空子抢占CPU资源的先前程序何时继续运行,完全不可控。
注意:批处理系统均不支持程序执行中与用户进行交互。
分时系统:
分时系统,基于上世纪出现的,中断技术、通道技术,两者之上发展出来的新型系统。
中断技术,上世纪60年代,计算机硬件发展出中断技术,CPU收到外部中断信号后,立即停下当前正在执行的事件,转而去处理其他事件,其他事件处理完成后返回之前中断的断点处继续执行之前的事件。
通道技术,专门处理外设和内存之间的数据传输处理机。
分时系统中主机以很短的“时间片”为单位,把CPU轮流分配给每个终端使用,直到全部作业被运行完。由于时间片很短,让每个终端都感觉自己好像独占了终端。切片由中断技术来实现,与内存间的交互由通道技术实现。
1.3.基本概念
本系列中只简单讨论操作系统的核心功能,即进程管理(CPU管理)、内存管理,关于这两大功能有一些前置概念:
- 存储
- 中断
- 系统调用
- CPU的态
备注:本篇文章只做简单讨论,会省去很多细节,后面有具体的文章对绝对标准的细节进行讨论。
1.3.1.存储
计算机的存储在《计算机组成原理》中已经讨论过,此处简单过一下。
寄存器:
寄存器中存放的是分配到时间片即将要执行的指令以及其需要用到的数据。
高速缓存:
高速缓存中存放的可能要用到的所有数据(当前没有分配到时间片)。匹配内存和CPU之间的读写速度差,实现局部性原理。高速缓存在落地实现时分为三级,一级更比一级的读写速度快,通过三级缓存,数据从内存级速度加速到CPU级速度。高速缓存与内存之间通过关联存储器以及目录来进行数据的关联。
主存:
RAM&ROM,主存是实际的地址空间,按字节编址。
辅存:
硬盘。
1.3.2.中断
中断,指CPU对外部的突发事件的反应机制,即中断当前执行的程序,转而执行其他程序。
CPU收到外部信号(中断信号)后,停止当前工作,转去处理外部事件,处理完外部事件后,回到中断处,继续原来的工作。
外部事件可能是一次鼠标的点击,一次键盘的输入,均可能。
外部事件发起中断信号,调用中断程序(系统中预先写好的程序),完成外部事件,返回断点处继续执行。
中断机制可以实现CPU和外设之间的并发活动,在中断机制出现之前,CPU和外设不能进行并发,也就是CPU在执行程序时,用户无法与之进行交互。用户一旦可以与CPU进行交互,也就意味着,用户可以对CPU的执行顺序进行一定程度的强制管理。CPU和外设可以并发执行,当然这里的并发不是指绝对并行的并发,而是指混合执行,只是时间间隔很短,感觉上像并发。
1.3.3.系统调用
系统调用是与操作系统交互的方式。用户与操作系统进行交互的方式不外乎以下几种:
- 图形界面
- 命令行
- shell、批处理
- 应用软件
这三种方式其底层都是调用操作系统提供的一系列接口去与操作系统进行交互,这些接口称为程序接口,也叫系统调用,即一组与硬件交互的服务,调用它们可以完成与硬件的各种交互,这些服务是操作系统封装好的,以便于调用的形式(一般是函数)对外暴露。
不同操作系统的系统调用,均遵守IEEE制定的POSIX标准(portable operation system interface of unix),也就是说不同系统的系统调用是相同的,其函数名、参数、各个函数对应的作用都是相同的。
之所以要封装出系统调用这一层,是基于以下两点考虑:
方便
- 安全
方便:
与硬件交互本身就十分繁琐,封装出接口便于用户操作。
安全
如果各个程序都能直接去与硬件进行交互,而缺乏中间层的监管,会十分混乱和不安全。
因此系统调用其实是为了合理化的一个架构而抽象出来的中间层。
此处以微内核架构的操作系统为例(Linux、Unix),与硬件(外设、内存、CPU等一切硬件)直接交互的功能存放在内核中,以系统调用的方式提供给程序:
调用系统调用时提供这些服务时,一般涉及核心资源或者硬件,CPU处于核态,调用时会产生中断。
1.3.4.CPU的态
CPU的态的出现是为了保证安全。操作系统在启动后,内存被分为两部分(两段):
- 内核段
- 用户段
内核段:
从0地址开始编址,存放操作系统程序
用户段:
从内核段之后开始编址,存放用户程序
由于内核段存放的是系统相关的内容,基于安全的考虑,肯定是不允许被CPU随意访问的,需要特权才行。因此将CPU的权限设计为了两种状态:
- 用户态
- 内核态
用户态:
只能访问用户段
内核态:
能访问用户段和内核段
CPU负责处理、执行指令,指令中有一些系统级别的特权指令,此类指令拥有极高权限,需要使用到内核段的系统资源,CPU需要从用户态切换到内核态,执行完特权指令后又切回用户态,这种CPU态的切换回带来的很大的性能问题。
在讨论这个性能问题的起因前需要了解一个前置概念——CPU的上下文,因为性能问题就是和上下文的切换有关。
CPU的上下文:
程序是被存放在计算机的内存中的,CPU要运行程序必须要知道程序存放在哪里,这样CPU才能去拿到程序,CPU的寄存器里有张“目录”记录了要运行的程序存放在内存的哪里。而又由于中断机制的出现,多个程序是被交替执行的,因此CPU还有个程序计数器,用来记录当前程序执行到了哪里,方便下次继续执行。程序计数器、寄存器是CPU运行程序时必须依赖的前置条件,因此这两个东西合称为CPU的上下文。
CPU态的切换造成的性能问题:
CPU态的切换会引起CPU上下文的切换,之所以CPU态的切换会引起CPU上下文的切换是因为,要访问“内核段”里的资源,那么上下文里记录的那张“目录”就必须换成内核段的目录,这样CPU才能找的到要的资源在哪里。上下文切换时会先把前一个任务的 CPU 上下文( CPU 寄存器和程序计数器里的内容)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。明显可以看到整个过程要刷新好几次整个上下文,这是非常耗时的。
之所以要将前一个上下文保存起来,是基于性能考虑。
假设执行三条指令ABC AC,用户级指令 B,内核级指令
执行A时,“局部性原理”驱使寄存器在用户段加载需要的数据以及可能会用到的数据。
执行B时,“局部性原理”驱使寄存器在内核段加载需要的数据以及可能会用到的数据,卸载掉原来的老数据。
执行C时,“局部性原理”驱使寄存器在用户段加载需要的数据以及可能会用到的数据,卸载掉原来的老数据。
根据“局部性原理”,ABC指令是连续执行的,AC之间的数据很可能是共用的,但是由于中间执行B指令,就造成了额外的一次重新寻址加载数据的时间。
所以把前一个不同级别的指令的上下文保存起来是个不错的优化方法,避免了额外的重复寻址,减少了额外的时间开销。
总的来说为了保证多数情况下程序执行的效率,“局部性原理”是必须存在的,为了内核的安全,CPU态的划分是必须存在的。所以,CPU上下文切换是不得不接受的一种代价。