冯诺依曼体系(VonNeumannArchitecture)
现代计算机,大多遵守冯诺依曼体系结构
CPU中央处理器:进行算术运算与逻辑判断
存储器:分为外存和内存,用于存储数据(使用二进制存储)
输入设备:用户给计算机发号施令的设备
输出设备:计算机给用户汇报结果的设备
针对存储空间:硬盘 > 内存 >> CPU
针对数据访问速度:CPU >> 内存 > 硬盘
CPU基本工作流程
指令(Instruction)
主要有操作码 + 操作数组成,其中操作码用来表示要做什么动作,操作数是本条指定要操作的数据,可能是内存地址,也可能是寄存器编号等
一个CPU能执行哪些指定,可以认为是CPU最初设计的时候,就已经确定好了,存在一个“表格”描述了都有哪些指令
下面是一个简化的指令表(Instruction Table):
指令(instruction) | 功能说明 | 4位 opcode | 操作的地址或者寄存器 |
LOAD_A | 从 RAM 的指定地址,将数据加载到 A 寄存器 | 0010 | 4 位 RAM 地址 |
LOAD_B | 从 RAM 的指定地址,将数据加载到 B寄存器 | 0001 | 4 位 RAM 地址 |
STORE_A | 将数据从 A 寄存器写入RAM 的指定地址 | 0100 | 4 位 RAM 地址 |
ADD | 计算两个指定寄存器的数据的和,并将结果放入第二个寄存器 | 1000 | 2 位的寄存器 ID 2 位的寄存器 ID |
tips:
AB名字是虚拟的,真实的cpu寄存器的名字,如:eax、ebx、esp、ebp....)
此处假设每个指令只有 8 bit ,实际一个指定很长
8 bit 的指令,分成两部分,前4 bit 是操作码表示指定是干啥的;后4 bit 是操作数(类似于参数)
执行指令的三个重要阶段
1. 取指令:cpu从内存中读取到指令内容到cpu内部(有专门的寄存器保存读到的指令)
2. 解析指令:识别出这个指令是干啥的,以及对应的功能和操作数
3. 执行指令
执行示例:
给一段内存空间,以及里面的数据
cpu中存在一个特殊的寄存器“程序计数器”,保存了接下来要从哪个内存位置来执行指令,本例可以认为程序计数器被设为0,接下来从0号内存地址开始执行指令,同时随着指令的执行,该处的值会自增更新(这是顺序执行的情况,若遇到“跳转类语句”(if、while、for、函数调用...)会被设为其他的值,本例不考虑)
1. 初始情况下,程序计数器是0值
a. 读取指令:00101110
b. 解析指令:
c. 执行指令:把14地址的内存数据读出来,放到寄存器A中
第一条指令执行完毕,系统自动将程序计数器中的值++,从0 -> 1
2. 执行地址为1的指令
a. 读取指令:00011111
b. 解析指令:0001 1111
查看指令表可知,该指令是LOAD_B,把1111地址上的数据读取到寄存器B中
c. 执行指令:把15地址的内存数据读取出来,放到寄存器B中
第二条指令执行完毕,系统自动将程序计数器中的值++,从1 -> 2
3. 执行地址为2的指令
a. 读取指令:100000100
b. 解析指令:
c. 执行指令:
将17的二进制存储到寄存器A中
第三条指令执行完毕,系统自动将程序计数器中的值++,从2 -> 3
4. 执行地址为3的指令
a. 读取指令:01001101
b. 解析指令:
查看指令表可知,该指令是STORE_A,将数据从A寄存器写入1101地址的内存中
c. 执行指令:
第四条指令执行完毕,系统自动将程序计数器中的值++,从3 -> 4
5. 执行地址为4的指令
a. 读取指令:00000000
b. 解析指令:程序执行结束
上例就是CPU完成 3 + 14 的过程
操作系统(OperatingSystem)
操作系统是⼀组做计算机资源管理的软件的统称。⽬前常⻅的操作系统有:Windows系列、Unix系 列、Linux系列、OSX系列、Android系列、iOS系列、鸿蒙等。
一个操作系统要做很多事,其中最重要的就是“管理”:
1. 管理不同的硬件设备:键盘、显示器、打印机、医疗设备...
2. 给软件提供稳定的运行环境,现代操作系统上要同时运行很多程序,希望这些程序之间不能相互干扰
操作系统 = 内核 + 配套的应用程序
对于操作系统内核来说,其包含的功能是非常多的,其中有一个功能和日常开发息息相关,那就是进程管理
进程/任务(Process/Task)
进程就是正在执行的应用程序,进程是操作系统进行资源分配的基本单位
由于一个系统上进程比较多,需要管理,分为两部分:
1. 描述:通过 结构体/类 ,把进程的各种属性表示出来(对于Linux操作系统来说,使用“PCB(继承控制块)”这样的结构体来描述进程信息
2. 组织:通过数据结构,把多个结构体穿起来,并进行增删查改操作(可以简单的认为,是通过链表的方式,把上述多个PCB串到一起,实际情况会更复杂)
PCB中的关键信息
1. PID进程的标识符
同一时刻,一个机器上的多个进程之间,PID是唯一的,不会重复的,系统内部很多操作都是通过PID找到对应的进程的
2. 内存指针(一组)
描述进程依赖的指令和数据都在内存的哪个区域
操作系统运行exe就会读取exe中的指令和数据,加载到内存中(侧面表示出,进程的执行需要一定的内存资源)
3. 文件描述符表(顺序表/数组)
描述了进程打开了哪些文件(对应到硬盘上的数据,侧面表示出,进程的执行,需要一定的硬盘资源)
进程中,打开了某个文件,就会在顺序表中添加一项
tip:进程的调度
操作系统进程调度的关键:分时复用
并发执行:只有一个核心的cpu,一会运行进程1,一会运行进程2,一会运行进程3...由于cpu运算速度非常快,使得切换速度也非常快,肉眼察觉不到,站在宏观角度(人的角度),同时执行,称为并发执行
并行执行:现在有了多核心的cpu,此时,每个核心和核心之间,微观上也能同时执行不同的进程,称为并行执行
并发和并行都是操作系统内核同意调度的,程序员/普通用户,感知不到
因此,平时把并发和并行统称为“并发”,对应的编程手法也成为并发编程
以下4点均属于进程的调度
4. 进程状态
就绪状态:随时可以被调度到cpu上执行指令
阻塞状态:无法调度到cpu上执行,之所以阻塞,是因为要做一些其他的工作,比如:IO操作(读写硬盘/读写网卡...)
像C中的scanf和Java中的Scanner执行到这样的语句都会发生阻塞
除了上两种状态,进程还有其他的状态,此处不展开
5. 进程优先级
根据进程情况,给与相应的优先级
6. 进程的上下文
分时复用,一个进程执行一会之后,就从cpu上调度走,过一段时间,会调度回cpu,沿着上次执行的结果继续往后执行,将上次执行的中间结果(各种cpu寄存器中的值)保存起来,以备下次使用,此为进程的上下文
7. 进程的记账信息
在优先级的加持下,使得不同进程吃到的资源擦会议越来越大,操作系统统计每个进程在cpu上执行的时间,根据这个来进一步的调整调度的策略
以上7中属性相互配合,共同构成了进程调度的核心逻辑
上述的调度过程均为系统内核负责完成