3.计算机是如何工作的(进程调度与管理详解)
目录
一、前言回顾
计算机是如何工作
操作系统
进程(任务)
进程管理
PCB 核心属性
二、本课内容
进程调度
4. 进程状态
5. 进程的优先级
6. 进程的上下文
7. 进程的记账信息
PCB 属性汇总
进程隔离性
进程间通信
一、前言回顾
计算机是如何工作
CPU 的工作过程~
以3 + 14为例,对应的指令序列为:
LOAD A
LOAD B
ADD
SAVE A
CPU 执行指令分为三步:
取指令
解析指令
执行指令
操作系统
操作系统的核心作用:
对下,管理各种硬件设备
对上,给各种软件提供稳定的运行环境~
进程(任务)
运行起来的程序~
二进制的可执行文件(硬盘)→ 运行后得到进程(内存)
进程是操作系统资源分配的基本单位。
进程管理
进程管理的两个核心动作:
描述:使用 PCB 结构体,把进程的各种属性表示出来。
组织:通过双向链表,把多个 PCB 串起来~~
PCB 核心属性
PCB(进程控制块)的核心属性包括:
PID
内存指针
文件描述符表
二、本课内容
进程调度
假设 CPU 核心有 20 个,但进程数上百个。如何利用有限的 CPU 核心,让这么多进程“同时执行”?
CPU 通过并行和并发两种方式实现:
并行:两个 CPU 核心,分别执行不同进程的指令。
并发:一个 CPU 核心,通过“分时复用”方式,实现“同时执行”(CPU 单核心时代,多任务操作系统全靠并发)。
→ 程序员感知不到 N 个进程之间是并行还是并发,都是操作系统自身负责调度的。咱们写代码,不关心并行还是并发,后续把并行和并发统称为并发。
4. 进程状态
进程有很多种状态,简单理解分成两种:
就绪:默认情况下,ABC 三个同事都处于“就绪”状态(“随时可安排工作”)。
阻塞:比如有一天,A 要出差~~ 出差的时间里,就无法给 A 安排工作了吧~~ 此时“阻塞”。阻塞意味着该进程无法参与到 CPU 的调度执行上~~
以前也接触过阻塞~
像scanner.nextInt()这样的代码会使你的进程阻塞~~
System.out.println("请输入要插入的 id:"); int id = scanner.nextInt();这里是需要等待用户输入的~~
5. 进程的优先级
ABC 我排工作日程的时候,不是完全公平的~~
周一周二周三:安排 A 的工作 (A 负责核心模块开发,优先级高)
周四周五周六:安排 B 的工作 (B 负责测试联调,也是重要任务)
至于 C,看整体进度了~~ 假设如果 B 的工作遇到阻塞,把 B 的时间匀出来一天,给 C 安排工作~~
进程的优先级,决定了哪个进程要优先安排 CPU 资源~~
你的电脑上,同时运行着开发环境和即时通讯软件
同事发来紧急消息,需要立即响应 → 实时操作~~ 有更多的 CPU 资源~~
有些特殊设备,优先级更关键~~ 汽车的智能驾驶系统~~ 负责刹车任务,优先级一定得是最高的~~
6. 进程的上下文
一个进程调度到 CPU 上执行了,离开 CPU,过一段时间,还会回到 CPU 上~~
离开时:保存信息(类似于项目的存档功能~~)
回来时:继续之前的位置往下执行(读档)
在给 ABC 三位同事安排工作的过程中,需要准备“工作日志”详细记录每次工作后的进度~~ 把关键事务记录下来~~
我在安排 A 的工作时,A 说:下周一要提交模块一的设计文档,你记得跟进一下~~ 我说好的,于是就需要记录到工作日志上~~
我在安排 B 的工作时,B 说:下周三要和客户联调,需要提前准备测试数据,你也跟进一下~~ 我也说好的,也需要记录到工作日志上~~
→ 这就是上下文~~
CPU 内部有很多寄存器~~ 用于保存当前程序运行的一些中间状态~~
除了保存数据的寄存器之外,还有一些特殊的寄存器:
记录当前指令执行到哪一条了~~
记录当前程序的函数调用关系
进程在 CPU 上执行的时候~~ 寄存器的值不停发生变换~~
进程要离开 CPU 的时候,把这一时刻,CPU 上这些寄存器的值,全都拷贝出来,保存到内存里(PCB 的结构体)→保存上下文(存档)
进程后续回到 CPU,也是把之前 PCB 保存的这些寄存器的值,重写入到 CPU 的寄存器中~~→恢复上下文(读档)
上述功能操作系统内部实现好了~~
7. 进程的记账信息
统计机制,统计每个进程,都在 CPU 上运行了多久~~
优先级机制下,就可能使某个进程吃到的 cpu 资源非常少。通过记账信息,识别出这一点,从而灵活调整,给这个进程多分点资源~~
PCB 属性汇总
PCB 中属性非常非常多~~ 包括:
PID
内存指针
文件描述符表
状态
优先级
上下文
记账信息
→ 这些属性支撑进程调度~~
进程隔离性
每个进程有自己独立的内存空间(进程的隔离性)
事务隔离性:多个事务同时执行,不要相互影响
进程隔离性:多个进程执行的时候,也不要相互影响~~
之前学 C 的时候,指针~~
int* p = &a; *p = 100;p = 0xaabbccdd → 能否通过这样的 *p 操作,修改别的进程的内存数据呢?
→不能~~
操作系统要给应用程序提供稳定的运行环境~~ 操作系统给每个进程划分了独立的内存地址空间~~ 每个进程只能访问自己的内存数据~~ 无法访问别的进程的内容~~
进程间通信
如果确实有时候需要多个进程协同工作~~ ⇒ 进程间通信了~~
常见的进程间通信方式:
管道
共享内存
文件
网络
信号量
信号
在 Java 生态中,不鼓励使用多进程编程。
这些机制很多在 JVM 中并没有封装~~
确实想进行多进程编程,Java 的生态中最推荐的方式是:网络
