携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
弱弱的问一问: 要操作系统干嘛?
这里先不讲操作系统的概念了,因为文字太生硬了,我们只需要看一个简单的例子:
- 在我们的JS代码里,只需要输入
console.log(1+1); 就可以在浏览器面板中看到2,这其中发生了什么事情呢?(简单扫一眼) - 首先键盘输入代码
1+1到显示器输出2, 需要CPU控制键盘(输入设备) ,将获取的1+1指令放入内存 - 然后CPU的控制器从内存中取出指令,并分析出指令是让计算机做一个
1+1的加法运算 - 此时CPU的控制将控制CPU的运算器做
1+1的加法运算,并得出结果2 - 最后CPU控制器控制运算器将结果返给内存,内存也在CPU控制器的控制下,将结果
2返回给屏幕(输出设备)
好了,这里问题是,如果没有操作系统,一个简单的1+1运算,你的js代码还需要考虑这些硬件的协调工作,比如你的代码要协调CPU资源什么时候读取你的代码,什么时候把进程切换到别的进程。。。这些脏活累活都是操作系统帮你屏蔽了,要不这代码可咋写啊。。。
弱弱的问一问: 前端学这个干嘛?
很早以前看朴零大神的《深入浅出NodeJS》的时候,讲到进程间通信,有一句大概说,windows平台进程间通信用的是管道,linux平台用的是domain socket,我一看就傻眼了,啥是进程间通信?啥是管道?啥是domain socket?😭 看不懂啊.... 这些都是跟操作系统进程的知识相关)。
啥也了不说了,兄弟,学习的小车已经粗发了!
2、操作系统运行机制和体系结构
预备知识: 什么是指令(更详细内容请看我的计算机组成原理文章)
比如说,如下图(简单扫一下即可):
a+b是一段程序代码,a+b在CPU看来并不能一步完成,可以翻译成如下:
// 意思是将内存的16号单元数据,放到A寄存器,
LOAD A, 16
// 意思是将内存的16号单元数据,放到B寄存器
LOAD B, 17
// 存器里的A,B数据相加,得到C
ADD C, A, B
复制代码
这里就可以看得出来,指令是CPU能识别和执行的最基本命令。
2.1 两种指令、两种处理器状态、两种程序
假如说一个用户可以随意把服务器上的所有文件删光,这是很危险的。所以有些指令普通用户是不能使用的,只能是权限较高的用户能使用。此时指令就分为了两种,如下图:
这就引出一个问题:CPU如何判断当前是否可以执行特权指令? 如下图: CPU通常有两种工作模式即:
内核态和用户态,而在PSW(这个不用管,就知道有一个寄存器的标志位0表示用户态,1表示核心态)中有一个二进制位控制这两种模式。
对于应用程序而言,有的程序能执行特权指令,有的程序只能执行非特权指令。所以操作系统里的程序又分为两种:
2.2 操作系统内核简单介绍
从下图,我们先看看操作系统内核包含哪些
操作系统内核中跟硬件紧密相关的部分有:
- 时钟管理。操作系统的时钟管理是依靠
硬件定时器的(具体硬件怎么实现我也不太清楚,好像是靠硬件周期性的产生一个脉冲信号实现的)。时钟管理相当重要,比如我们获取时间信息,进程切换等等都是要依靠时钟管理。 - 中断处理(下一小节会详细介绍)。
- 原语(后面会有案例提到)。现在可以简单理解为用来实现某个特定功能,在执行过程中
不可被中断的指令集合。原语有一个非常重要的特性,就是原子性(其运行一气呵成,不可中断)。
2.3 中断
- 在程序运行过程中,系统出现了一个必须由CPU立即处理的情况,此时,CPU
暂时中止程序的执行转而处理这个新的情况的过程就叫做中断。 下面举一个例子:
第一个应用程序在用户态执行了一段时间后
接着操作系统切换到核心态,处理中断信号
- 操作系统发现
中断的信号是第一个程序的时间片(每个程序不能一直执行,CPU会给每个程序一定的执行时间,这段时间就是时间片)用完了,应该换第二个应用程序执行了 - 切换到
第2个进程后,操作系统会将CPU的使用权交换给第二个应用程序,接着第二个应用程序就在用户态下开始执行。 进程2需要调用打印机资源,这时会执行一个系统调用(后面会讲系统调用,这里简单理解为需要操作系统进入核心态处理的函数),让操作系统进入核心态,去调用打印机资源- 打印机开始工作,
此时进程2因为要等待打印机启动,操作系统就不等待了(等到打印机准备好了,再回来执行程序2),直接切换到第三个应用程序执行 - 等到打印机准备好了,此时打印机通过I/O控制器会给操作系统发出一
个中断信号,操作系统又进入到核心态,发现这个中断是因为程序2等待打印机资源,现在打印机准备好了,就切换到程序2,切换到用户态,把CPU给程序2继续执行。
好了,现在可以给出一个结论,就是用户态、核心态之间的切换是怎么实现的?
- "用户态 ---> 核心态"是通过中断实现的。
并且中断时唯一途径。 - "核心态 ---> 用户态"的切换时通过执行一个特权指令,将程序状态的标志位设为用户态。