计算机是如何工作的
- 冯诺依曼体系
- 操作系统
- 操作系统的概念与定位
- 进程和任务
- 操作系统对进程的管理
- PCB 的相关信息
冯诺依曼体系
现代的大多数计算机, 都遵循冯诺依曼体系
- CPU 中央处理器: 进行算术运算和逻辑判断
- 存储器: 分为外存和内存, 用于存储数据(使用二进制方式存储)
- 输入设备: 用户给计算机发号施令的设备
- 输出设备: 计算机个用户汇报结果的设备.
CPU 内存 磁盘的比较
- 存储空间上
- CPU << 内存 < 磁盘
- 读取速率上
- CPU >> 内存 > 磁盘
寄存器 和 内存
- 寄存器是CPU的一部分;
- 寄存器, 和内存与磁盘相比, 存储空间更小, 访问速度更快, 成本更高, 掉电后数据丢失。
- 寄存器的速度和内存的速度的差距是极大的,3~4个级别
- 寄存器的用途,就是辅助 CPU 完成指令的执行;一条指令,不仅仅是指,指令本身,同时还有操作数,操作数就是要在寄存器中保存的
由于 寄存器 和内存之间速度和空间上差异太大了,难以协调工作,CPU往往又引入了“缓存”来调和 寄存器 和 内存之间的速度。
CPU 上要进行一系列运算,在运算过程中,要反复使用到一组内存中的数据,这些数据频繁使用,需要频繁访问内存,同时这些数据又比较多,在寄存器里又存不下,就可以放到缓存中了。
缓存的存储空阿金介于 寄存器 和 内存 之间
由于寄存器和内存之间,差距太大了,搞了一个缓存,还不太够用,后来又搞了一个。
操作系统
操作系统的概念与定位
-
操作系统是一个软件, 是一个搞管理的软件
- 对下,要管理好各种硬件设备
- 对上, 要给各种软件提供好一个稳定的运行环境
- 例如: CPU, 内存, 硬盘, 各种IO设备 … 他们都是需要相互配合才能进行良好的工作的, 操作系统这个软件, 就是总指挥!
-
计算机如何给我们解决实际问题的?
- 依靠一些软件, 软件能够在操作系统上运行
- 硬件千差万别,如果每个写软件的人, 都需要考虑硬件的差别和兼容性, 这个事情门槛就非常搞了, 操作系统, 就把硬件屏蔽起来, 对软件这个里提供出一组API(系统调用), 让软件来进行调用
- 因此, 操作系统 和 JDBC 这个层面上干的是类似的工作
- 依靠一些软件, 软件能够在操作系统上运行
进程和任务
- 运行起来的程序叫做进程
- 程序就是一个可以执行的文件, 只是磁盘上的一个东西
- 如果双击程序, 此时操作系统, 就会把可执行文件中的数据和指令, 加载到内存中, 并且让 CPU 去执行这里的指令, 完成一系列的相关的工作. 运行起来的(动态的程序) 就是进程了
- 进程能够干活, 说明进程能够消耗一定的硬件资源.
- 可执行程序, 只是占用了硬盘空间; 而进程, 会消耗 CPU资源, 内存资源, 硬盘, 网络带宽…
- 进程是系统分配硬盘资源的基本单位
操作系统对进程的管理
管理的概念
- 为什么需要管理进程?
- 一台正在运行的计算机, 一定会存在很多的进程正在运行;
- 东西多了, 那很定就是需要进行管理, 才能让各个进程发挥自己的能力, 并将这些能力有效的组织起来, 高效的完成指定的工作
- 如何进行有效的管理?
- 管理不是"面面俱到" 不是"手把手", 这样会不仅累, 还低效
- 高效管理的两大步骤: 先描述, 在组织
-
- 先描述: 提取要管理对象的基本信息与属性, 使用结构体或者类将其描述起来
-
- 在组织: 选用合适的数据结构, 对于新来的对象, 就通过 add 方法, 将新来的对象添加到数据结构中, 此时对于对象的管理, 就转化成对数据结构的增删改查操作了。
-
操作系统对进程的管理的组织过程
- 描述: 会用使用一个专门的结构体, 来记录一个进程里面的各个属性
- PCB (进程控制块) --> 通用叫法, 各种系统里面描述的进程部分都可以称为PCB
- 在Linux中PCB, 源码中是一个 task_struct 结构体
- PCB (进程控制块) --> 通用叫法, 各种系统里面描述的进程部分都可以称为PCB
- 组织: 会使用一系列的数据机构, 把多个进程进行一个有效的组织, 随时方便进行遍历, 查找, 汇总数据 …
- 通常是使用双链表这样的方式来进行组织的 – 这个是对Linux来说的
- 当使用双链表来组织的时候:
- a) 查看进程的列表, 本质就是在遍历这个链表
- b) 创建一个进程, 就是创建了一个 PCB结构体,并且插入到链表上
- c) 销毁一个进程, 本质就是把这个PCB结构体从链表上删除并释放
PCB 的相关信息
- pid 进程的标识
- 同一个系统上, 统一时刻中, 每个进程的 pid 一定都是不同的
- 内存指针
- 表示了该进程, 对于的内存资源是什么样的
- 主要存储的就是从 exe 可执行文件中加载过来的指令(二进制的指令, 都是在程序员开发这个程序的时候, 最终编译生成的结果,也就是程序员写代码的逻辑) 和 数据
- 指令相当于剧本, 进程就相当于表演的舞台
- 还需要保存一些运行过程中的中间结果之类的的数据
- 文件描述符表
- 和磁盘资源相关了
- 磁盘是硬件, 应用程序一般是没法直接接触到 “硬件” 这一层的.
- 实际上是操作系统抽象"文件"这样的概念, 程序操作的是文件, 文件实际上是存储在磁盘上的
- 每个进程就会一个 “文件描述符表” 来记录 当前这个进程在使用哪些文件
- 操作系统在打开一个文件, 就会产生一个 “文件描述表”(就像文件的身份表示一样, 当然只是在进程内部生效的)
- 同时会使用文件描述符表(类似数组), 包文件描述符组织起来
CPU 与 进程 之间的联系
- 进程是需要在CPU上来执行指令的
-
每个进程, 要想执行里面的指令, 完成对应的任务, 都需要在 CPU 上执行!
-
问题提出: 一台机器上, 进程同一时刻, 有百八十个, 但CPU只有一个? 怎么办?
- 轮着用就可以了, 进程的调度
-
- CPU的发展历程
- CPU一开始是单核的, 只能运行同时一个进程在上面运行
- 摩尔定律: 芯片的集成程度会成倍增长, 算力会提供一倍, 成本会减半
- 但是随着时间的增长, 摩尔定律就失效了, 因为芯片再小, 经典物理学就失效了, 量子物理学此时就生效了 – 所以芯片的继承程度不会一直增加
- 集成程度失效了, 那就靠数量来凑 – 多核CPU
- 又提出来超线程概念: 一个CPU可以同时跑两个进程
- 现在的CPU就是多核多线程 – 例如六核十二线程
CPU虽然可以让多个进程同时在一起跑来了, 但是还是不能满足所有进程, 因为CPU是有限的, 进程的数量远大与CPU的数量, 解决方法就是轮着来, 以下是解决方案:
- 并行: 同一时刻, 两个进程, 同时运行在两个 CPU 逻辑核心上
- 并发: 两个进程, 在同一个舞台上, 轮着上
- 由于 CPU 切换进程速度极快, 微观上, 这两进程是串行执行的; 宏观上, 看起来就是这两个进程在 “同时” 执行的
- 操作系统, 在调度这些进程的时候, 可能是按照并行的方式来调度, 也可能按照并发的方式来调度, 在应用程序这一层, 感知不到~
- 由于感知不到是哪种方式调度, 并且这两种的调度方式, 宏观上的体现效果都是一样的, 通常也会用 “并发” 这个词来代指 “并行” 和 “并发”
- PCB 中关于进程调度相关的属性(这些属性也就描述了 进程 对于的 CPU 资源的使用情况) – 需要重点掌握
-
- 状态
- 就绪状态: 一个进程已经随时做好了在CPU上执行的的准备
- 就绪状态的意思是: 可能在CPU上跑, 也可能没有在CPU上, 而是已经做好了被CPU调度的准备
- 阻塞状态 / 睡眠状态 : 有时候, 进程没有准备好呗调度到CPU上
- 状态是可以相互转换的
- 进程还有许多状态, 但是就绪和阻塞是最重要的两种状态
-
- 优先级
- 系统给进程进行调度的时候, 也是不完全公平的, 也会根据优先级的不同, 来决定事件的分配权衡 – 这样就可以把系统资源调配给更重要的进程上了
-
- 上下文
-
因为进程是轮着上的 – 所以一次执行, 大概率是无法完成指定的任务的, 这就需要保证下次上 CPU运行的时候, 能够找到上次运行的位置, 继续向后运行
-
就好像存档 读档一样
-
对于操作系统来说, 所记录的上下文是啥? 就是该进程在执行过程中, CPU寄存器中对应的数据 - 这些寄存器, 有的是存一些中间结果, 有的是存一些特定含义的数据(比如下一条指令时在哪里, 比如当前的函数调用关系…)
- 这些寄存器中的数据就需要在进程离开 CPU之间, 都保存好
- 保存到对应进程的 PCB 的上下文字段中(内存中)
- 下次该进程回到 CPU 执行, 就可以把PCB中的上下文里的数据恢复到对应的寄存器中, 这个时候就是和上次执行的状态一模一样了
-
- 记账信息
- 相当于一个统计信息, 会统计每个进程在 CPU 上都执行了多久, 执行了多少指令.
- 是对于进程调度工作的一个"兜底"
- 用来调整如何分配给进程的调度时间
进程地址空间(虚拟地址空间)
- 进程地址空间提出的原因
-
每个进程都需要分配到系统资源, 内存也需要分配给进程; 如果内存直接分配给进程, 此时别的进程就可能看到其他进程的相关信息,并将其修改, 导致其他的进程崩溃;
-
并且, 直接分配内存空间, 会存在分配地址范围的不同, 且是未知的, 每个进程就需要对不同的地址进行不同的处理, 这样的代码编写会变得复杂.
-
所以为了解决上述的问题, 在进程和内存之间提出了一个进程地址空间的概念
-
- 进程地址空间的解决原理:
- 对于非法访问地址空间的问题: 进程现在只能找进程地址空间上的地址, 操作系统在对该进程地址空间上的地址进行判断, 如果是该进程的–也就是合法的, 那操作系统在通过该虚拟地址找到所对应的物理内存的地址, 如果虚拟地址是非法的, 那么操作系统就不会允许该进程使用该地址, 并直接向该进程发送中断信号.
- 对于地址不统一, 编写代码复杂的问题: 每个进程得到都是用同样的进程地址空间, 进程地址空间设计的时候是一样的, 所以每一个进程看到自己的进程地址空间, 结构上都是一样的, 所以代码就可以统一对该进程地址空间进行编码, 对应实际物理内存空间就交给操作系统来分配了
进程间通信
- 进程地址空间将进程独立开来, 每个进程只能看到自己的资源, 无法看到别人的资源, 也就无法影响别的进程, 但是, 两个进程也就无法进行信息交流了
- 但是, 有时候, 我们需要两个进程之间进行通信 – 所以, 我们就提出了进程间通信的概念
- 进程间通信核心: 让两个不同的进程看到同一份资源!
- 进程间通信方案:
-
- 基于文件
-
- 基于网络
-