操作系统的基本概念

“差不多”精神

操作系统是人造科学,其中蕴含着“差不多”的思想,学习操作系统不可吹毛求疵。

硬件知识

概念上的结构:

  • 一条总线,各种硬件挂在这根总线上;而每个硬件都是通过对应的控制器连接到总线与 CPU 通信。
  • 流水线是结构:为了提高效率,模仿工业流水线结构,即每一级都在工作,但是每一级的工作内容都不一样,呈时序关系。
  • 执行单元:缓存是让执行单元发挥最大利用效率的结构。
  • 存储结构:金字塔形,容量在增大,价格在降低;容量在增大,速度在减小。
  • 中断:OS 中最重要的机制,是 OS 获取PC 控制权的根本保证。

抽象

  • 根本上存在但是现实中不存在。
  • 来源于现实,统一于现实,超出现实。
  • 操作系统的抽象在于它来源于硬件,但超出了简单将硬件相叠加的功能,为上层应用提供了更大的资源。
  • 软件中不同功能块之间也是一种抽象,对其他功能块而言是一个完整的功能,而非细节描述。

内核态与用户态

  • 内核态
    拥有最多资源,最高特权。管理 CPU、内存、诊断测试、部分文件系统。
  • 用户态
    拥有有限的资源,有限的权限。应用程序的管理。
  • 状态的识别
    CPU 的状态字的设定,在一个程序运行时,此时 CPU 设定的什么状态这个程序就工作在什么态。
  • 实现
    这种两个状态相分离的实现,是通过“地址翻译”来实现,对用户态下的程序的每一条指令都会检查;而内核态下的程序可以绕过这个翻译。 这是否就为病毒提供可获取最高特权的可能?

操作系统的结构演变

微内核操作系统结构:

进程、内存、文件

  • 进程 - 在运行中的程序
  • 内存 - 进程的存放场所
  • 文件 - 程序和数据的最终存放点

系统调用

  • 操作系统是通过系统调用来为应用程序提高服务的。应用程序通过调用操作系统提供 的API来获得操作系统的服务。
  • 编译器对一个程序语句先将库函数扩展为系统调用函数,再继续执行。
  • 系统调用的种类
    • 进程类
    • 文件类
    • 设备类
    • 内存类
    • 信息维护类
    • 通信类
  • 系统调用的3个阶段
    • 参数准备,将参数放入寄存器或者压入栈
    • 调用识别,通过查询系统调用表或者系统调用函数的内存地址
    • 调用执行,执行这个内存地址的系统调用代码

Shell

  • 系统 API 过于复杂,是给专门的编程人员使用。而这个 Shell(壳) 就像是操作系统之上的一层壳,有固定的命令或图形操作方式给用户使用;用户可以通过这个 Shell 中的命令来调用系统服务,(固定的命令保证了用户不能直接使用用户态的核心服务,而是有界限的只用 Shell 提供的这些,保证了系统安全)。
  • 一个 Shell 就是一个循环程序,始终在等待用户的输入,当用户输入后程序继续执行并 fork 一个子进程来完成用户的命令任务,父进程等待子进程结束。

进程

进程是什么

进程 是正在运行中的程序,是对程序的抽象。也就是说,进程根本上是存在的,是人为定义的,但是物理意义上是不存在的,是抽象出来描述运行中程序的一个概念。

进程模型

进程带来的好处

  • 进程的发明让正在运行的程序的具体细节对用户而言是透明的,
  • 用户可以同时运行多个程序,并相对串行运行的程序而言可以更快的给出响应,降低了平均响应时间.
  • 极大的提高了 CPU 的效率

进程创立/产生/消失

进程创立

进程的创立需要 分配进程控制块 -> 初始化机器寄存器 -> 初始化页表 -> 程序读入内存 -> CPU 设置为 用户态 -> 跳转到程序执行的起始地址

  • Unix下
    • 第一步: fork A进程fork 一个与自己完全一样的进程B,
    • 第二步: exec 将 B 进程的地址空间用待要启动的程序内容来覆盖, 跳转到这个新程序的起始地址,开始exec
  • Windows 下
    没有fork 这个步骤,直接由系统调用来产生新的进程
  • 地址空间
    • 地址空间是进程执行的内存空间, 是进程执行的舞台,包含进程执行要用到的所有资源
    • 地址空间只是提供资源,真正使用这些资源的叫做线程,舞台上的演员.
    • 进程就是这场舞台剧

进程的产生

进程可以看做有多种类型, 系统进程/用户进程.

  • 系统初始化 -> 人类的诞生
  • 系统进程创建新的子程序,可以看做是操作系统自然产生的 -> 人类自然繁衍的孩子
  • 用户请求创建的新进程可以看做是用户人为创造的 -> 就像试管婴儿.
  • 然后子进程可能又会不断的产生新的进程.

进程的消失

进程的终止可以有下面几个原因:

  • 寿终: 进程完成任务后自然的退出结束.
  • 自杀: 进程自身发生错误, 退出结束.
  • 他杀: 被其他进程强行杀死
  • 处决: 进程产生异常, 被系统强制终结

进程的层次与状态

进程的层次

进程的层次:用户层/内核层
一个进程在执行过程中可以通过系统调用来产生新的进程, 新的进程叫做 子进程, 原来的进程就是它的 父进程. 在 Unix 系统中有父进程和子进程的概念.
在 WIndows 系统中不存在这种概念,认为所有的进程地位是平等的.

进程的状态

执行就绪阻塞

  • 执行 -> 就绪
    CPU 在执行A 进程的过程中, 考虑资源平均的因素, 自然切换到了B进程. 此时 A 进程进入到就绪状态,等待 CPU 的再一次执行.
  • 执行 -> 阻塞
    CPU 在执行 A 进程的过程中, 遇到需要 I/O 操作,此时 CPU 切换到其他进程, A 进程进入阻塞状态
  • 就绪 -> 执行
    A 进程一直在等待 CPU 在选择它来执行,一旦 CPU 选择了 A 程序, A 程序由就绪进入执行
  • 阻塞 -> 就绪
    A 进程在处理完 I/O 后,解除阻塞状态,等待 CPU 选择执行,此时正是处于就绪状态

特别的 :

  • 不存在 阻塞-> 执行 这个过程
    因为阻塞到执行中间必须经过就绪状态, 这是实际上可以操作的,但是阻塞在未进入就绪状态时由被 CPU 选择执行还是阻塞状态,这是没有意义的.

  • 不存在 就绪 - > 阻塞
    因为一个处于阻塞状态下的进程, 等待它的下一步操作必然是 CPU 来执行它,只有再执行后才会遇到 I/O 操作,进入到阻塞状态. 这是逻辑上行不通的.

  • 一个进程的生命周期

进程管理

  • 维护进程记录
    使用进程表,其中包括每个进程使用的寄存器,程序计数器,状态字,栈指针,优先级,进程的 ID,创建时间,使用 CPU 时间,等信息. 有些进程处于用户态,但进程表都在内核态.

  • 进程控制块,每个进程都有一个进程控制块,可以看做各个进程控制块构成了进程表。

    进程控制块,涵盖一个进程的所有信息

  • 进程在同一个时间只能干一件事情, 公平与效率,如何设置优先级都是总要的.

  • 线程的引入将会解决 同一时间只能做一件事的问题 和 整个进程都会被阻塞的问题(意味着进程中不宜懒于I/O 的部分也不能被执行推进,让整个进程的每一部分都停滞)