一、操作系统的发展历史
1、手工操作阶段
一开始人们用手工操作纸袋机的形式来让计算机处理文件,这首先需要涉及人为手工的给纸带机“装入纸带”、“取出纸带”,然后纸袋机再缓慢地“读取”、“写出”数据,但是这中间的计算机处理数据的速度其实很快很快(纸带机其实就是计算机的外部I/O设备)
弊端就是:
- 1、用户需要独占全机,同一个计算机必须得先完全完成一个程序进程(包括等待纸袋机将结果写完),才可以让下一个程序执行
- 2、人为操作的时间很久,纸带机读写的速度也超慢,其实计算机的处理速度是够快的,就是人和纸带机耽误了时间
2、批处理阶段
1)单道批处理系统
于是后面人们研究出“单道批处理系统”,由一个 “外围机” 先接收多个程序,然后将这些程序都提前写进一个【磁带】(磁带其实就是计算机的外部I/O设备)
【磁带】代替了 “纸带机”,它的读写速度远比 “纸带机”快
最后,计算机里存在一个【监督程序】,会自动监督一个程序的读写是否结束:当一个程序完全输出结果并写到另一个用来存结果的【磁带】之后,计算机再开始自动读取上一个【磁带】里剩下的程序,进行运算,然后再将结果输出给另一个用来存结果的【磁带】
虽然【磁带机】的优点有:
- 1、缓解人机速度矛盾
- 2、资源利用率提高
但是仍存在弊端:
- 1、内存中 仍然只能有一个程序运行
- 因为【磁带】的处理系统结构是单道的,只允许一个程序进行;而且前面用户的多道程序只是写到 “外围机” 里并提前存到【磁带】,但是计算机的 “监督程序” 仍会等待一个程序运行完,再去【磁带】里读取下一个程序
- 2、CPU仍有大量时间是在空闲等待I/O设备,资源利用率低
2)多道批处理系统
于是又诞生了躲到批处理系统,【磁带】和计算机之间允许允许多个程序
当一个程序运行时,CPU进行计算;然后当程序计算完毕,开始往I/O设备【磁带】写入结果,这个等待的时间CPU空闲了,那就可以马上对下一个程序运行计算;CPU计算完这个程序,然后输出结果之后,CPU再次空闲,再对下一个程序进行计算......
从而提高资源利用率
优点:
- 1、多道程序并发(还是有略微的先后顺序的)执行,共享计算机资源
- 2、资源利用率高
弊端:
- 没有人机交互功能(用户提交完程序之后,只能慢慢等计算机自己运行处理,直到全部结果输出,但是自己没办法再程序运行中途做一些操作)
3、分时操作系统
为了解决人机交互的问题,人们又设计了【分时操作系统】
原理就是计算机以时间片为单位,平等地轮流处理各个用户/程序服务。也就是【并发】的原理,分时段的、平均地执行各个程序
优点:解决了人机交互问题,用户请求可以被即时响应
缺点:不能处理一些紧急任务,因为是平均等时地分时执行程序
4、实时操作系统
【实时操作系统】就能弥补【分时操作系统】的不足,能够处理紧急任务
然后【实时操作系统】又分为【硬实时操作系统】和【软实时操作系统】,区别就是前者必须硬性要求一定要在规定时间内完成处理,后者允许偶尔违反规定时间
二、操作系统的运行机制
1、【指令】误区概念
【指令】就是处理器(CPU)能识别、执行的最基本命令,也就是汇编翻译上层后变成的一堆二进制代码
注:很多人习惯把 Linux、Windows、MacOs的 “小黑框” 控制台中使用的命令也称为 “指令” ,其实这是 “交互式命令接口”,注意与本节的【指令】区别开。本节中的【指令】指二进制机器指令
2、计算机两种程序
计算机有两大类程序:【应用程序】、【内核程序】
我们普通程序员写的程序就是【应用程序】
微软、苹果有一帮人负责实现操作系统,他们写的是【内核程序】,由很多【内核程序】组成了【操作系统内核】,或简称【内核(Kernel)】。【内核】是操作系统最重要最核心的部分,也是最接近硬件的部分
3、两种程序的指令权限
【应用程序】只能使用 “非特权指令” ,如:加法指令、减法指令等
【内核程序(操作系统的内核)】作为“管理者”,可以让CPU执行一些 “特权指令”,如:内存清零指令。这些指令影响重大,只允许 “管理者”——即操作系统内核来使用
在CPU设计和生产的时候就划分了【特权指令】和【非特权指令】,因此CPU执行一条指令前就能判断出其类型
4、CPU如何切换状态
CPU有两种状态:【内核态】、【用户态】
- 处于【内核态】时,说明此时正在运行的是【内核程序】,此时可以执行特权指令
- 处于【用户态】时,说明此时正在运行的是【应用程序】,此时只能执行非特权指令
拓展:计算机组成原理中讲过,CPU中有一个寄存器叫【程序状态寄存器(PSW)】,其中有个二进制位,1代表【内核态】,0代表【用户态】
那么CPU切换两种状态的过程就是:
- 【内核态】——>【用户态】:当执行到一条【特权指令】----- 修改PSW程序状态寄存器的标志位位 “用户态”,然后就意味着【操作系统】将主动让出对CPU的使用权
- 【用户态】——>【内核态】:由 “中断” 触发,会“被动or主动”地被夺走对CPU的使用权,CPU自动完成“变态”(变换状态),这意味着【操作系统】将强行夺走对CPU的使用权
注意:除了 “非法使用【特权指令】事件” 会触发【中断信号】,还有很多事件都会引发,但是共性都是——需要操作系统介入的事件,就会触发【中断信号】
(这里看不懂没关系,下面的例子以及后面提到的【中断】知识点会解释清楚)
举个例子:
—— 刚开机,CPU初始状态是【内核态】,操作系统的内核程序先到CPU运行,执行一些初始化操作
;
—— 开机完成后,用户可以启动某个应用,此时操作系统让出CPU使用权,PSW标志位变成“用户态”,CPU变态为【用户态】,应用程序到CPU运行
;
—— 此时有个黑客黑入应用程序,插入了一个【特权指令】,当CPU一条一条指令执行时,突然发现执行到了一个【特权指令】!!!!
;
—— 然后CPU检查PSW标志位,发现自己确实是【用户态】啊,那也就是说老子现在正在给一个“应用程序”执行【特权指令】?!倒反天罡!!
;
—— 于是这个 “非法使用【特权指令】事件” 会触发【中断信号】
;
—— 然后CPU检测到【中断信号】,马上自动变成【内核态】,然后操作系统 “趁虚而入,称王称霸”,这时就会停掉 “应用程序”,转而运行操作系统的“内核程序”了
;
—— 等到操作系统的“内核程序”执行完毕,再让出CPU使用权,然后CPU变回【用户态】,“应用程序”接着运行
【总结】
三、中断
前面知识点我们讲了,【中断】会引发CPU切换自身【用户态】变成【内核态】
如果一个计算机没有【中断】,那么一个程序就会一直无休止地永远运行下去,那怎么实现 “多道程序并发运行”?所以必须得有【中断】
那么【中断】具体有哪些类型?
1、内中断
内中断,顾名思义——中断信号来自于CPU内部
而CPU内部有什么?不就是正在运行的程序吗?因此【内中断】是与当前CPU执行的指令有关
触发【内中断】信号的原因主要涉及三种情况:【终止】、【陷阱、陷入】、【故障】
【终止】:就是前面我们讲的例子,比如假设一个应用程序在执行一个 “特权指令”,那么就是执行一个 “非法特权指令”,就会引发【中断】;还有像除数为0......等等这些异常错误,都会引起【中断】
- 注意:这是因为【非法指令】、【异常错误】...而导致了致命的错误,应用程序被动的被操作系统抢夺CPU使用权,而且通常操作系统内核程序执行完会直接终止原应用程序,不会继续让原程序接着回来运行了(因为你本来就有错、有危险了)
;
【陷阱、陷入】:当应用程序需要调用操作系统帮忙的时候,比如程序要用操作系统打开文件、修改文件...等等,此时应用程序会主动让出CPU使用权,CPU切换称“内核态”,然后操作系统调入,用完再还给“应用程序”接着运行
- 注意:这是应用程序主动交出CPU使用权给操作系统,是程序故意引发的,而且会让源程序接着回来运行,【系统调用】就是一种通过【陷入指令】实现的
;
【故障】:程序内部出现某些错误条件引发,需要内核程序来修复故障,修复完之后操作系统会让应用程序接着回来用CPU(具体以后会说,比较复杂)
2、外中断
外中断,顾名思义——中断信号来自于CPU外部
CPU外部没法运行程序,也就没法执行指令,因此【外中断】与当前CPU执行的指令无关
当CPU正常运行程序时,每执行一条指令,就要检查一次是否有外部中断信号
举一些外部中断的例子方便理解:
1、时钟部件控制中断:比如时钟部件会每隔一段时间,分片似的给各个进程运行,虽然cpu只能运行一个程序,但是有了时钟部件的分时控制之后,到了时间会换另一个程序到cpu运行,这就是为什么任务管理器那同时能有那么多进程在运行,而且那些性能每秒都在变,这就是因为时钟部件在以人肉眼察觉不到的速度合理地发出【中断】,来让操作系统的内核控制每个进程都能够 “并发” 运行
;
当然还有更简单的例子:
2、I/O设备也会发出【中断】信号,比如我们同时在用微信和QQ音乐的时候,QQ音乐放歌需要借用外部的音响(I/O设备),而微信此时也发来一个语音,微信因为要听语音所以要使用音响(I/O设备),然后音响(I/O设备)就会向CPU发送一个【中断】信号,然后CPU马上切换成【内核态】,操作系统内核就把QQ音乐赶下去,然后让微信上CPU并使用音响(I/O设备),操作系统自己也主动退下;等待微信这边用完了音响(I/O设备),音响(I/O设备)再次发出【中断】信号,然后操作系统再把微信赶下去,恭送QQ音乐登基CPU......
拓展:中断机制的基本实现原理
【总结】
这里再额外提一下,教材中会用【异常】——代替——>【内中断】的说法,用【中断】——代替——>【外中断】,这里需要知道
四、系统调用
1、啥是系统调用
前面我们第一章介绍操作系统的时候就说过,操作系统是介于底层硬件和上层用户和应用程序之间的软件,它为上层的用户和应用程序提供接口来服务,让用户和应用程序可以使用这个接口来调用操作系统去操作使用底层硬件
那么【系统调用】就是这个【接口】
学过开发的应该都知道【接口】是什么,对于编程语言而言,【接口】就是我们能够通过调用一个函数,来实现一些别人已经封装好的类里的功能;对于开发而言,【接口】就是前端能够通过调用一个函数,来实现后端提供的一些服务、功能;
那么【系统调用】就是操作系统提供给应用程序(程序员/编程人员)使用的接口,也可以理解为一种可供应用程序调用的特殊函数,应用程序可以通过【系统调用】来请求获得操作系统内核的服务
2、【系统调用】和【库函数】调用的区别
但是【系统调用】它是一种 “特殊函数”,不仅仅是像简单的 “库函数” 调用那样
【系统调用】是涉及更底层操作系统对硬件操作的服务,“库函数” 还在【系统调用】的上层;“库函数” 有的时候会不涉及【系统调用】直接为普通应用程序提供服务实现,有的时候也要再调用【系统调用】来让操作系统操作底部硬件。
3、
为什么要有【系统调度】呢?因为操作系统需要通过【系统调度】来控制协调计算机里的【共享资源】
假设一个共享资源——打印机,有两个程序都在并发运行,然后他们都在抢着用打印机,那么如果没有管控,随着程序并发运行,打印机就会被他两交替着用,最后打印出一篇混在一起的shit
那么系统调用的功能主要有下面这几种,了解即可
总而言之:应用程序通过【系统调用】请求操作系统服务,而系统中的各种共享资源都由操作系统的内核统一掌管,因此凡是与【共享资源】有关的操作(存储分配、I/O设备操作、文件管理.....),都必须通过【系统调用】的方式向操作系统内核提出服务请求
这也就能够保证系统的稳定性和安全性,因为用操作系统的内核的操作,能防止用户在应用程序进行非法操作
3、系统调用过程
首先CPU读取并执行一条一条应用程序里的指令,将指令以【参数】形式放至一个【寄存器】中,这个参数将指明系统调用的类型是什么
然后当遇到一个需要操作系统操控共享设备的指令,比如陷入指令时,CPU内部收到内部中断信号
然后CPU将自动转换称内核态,然后触发操作系统抢夺CPU使用权,这时就会调用【系统调用】的入口程序,然后CPU将接管并执行【系统调用】的入口程序的每一条指令
然后CPU会根据寄存器中的参数来判断用户需要哪一个【系统调用类型】,然后发送请求让操作系统的内核程序开始运行,于是【操作系统的内核程序】又来接管CPU使用权......
所以我们之前说【系统调用】就是通过【陷入指令】来执行的
但是注意!!!
- 1、【陷入指令】并不是【特权指令】!!!它只是一个特殊指令,是在【用户态】下执行的。执行了【陷入指令】之后才会立刻触发【内中断】,然后使CPU变成【内核态】
- 2、发出系统调用的请求是在【用户态】;而对系统调用的相应处理是操作系统的内核程序来做的,是【内核态】
- 3、陷入指令 = trap指令 = 访管指令(专业术语注意)