2.1 进程
多道程序设计中一个CPU在不同进程间切换形成伪并行的假象.
由此真正的并行的概念模型逐渐出现
2.1.1进程模型
进程模型中,所有可运行的软件(包括操作系统)被组织成若个顺序进程sequential process 也叫进程process
- 进程与程序的区别、关系?
进程是某种类型的一个活动,有程序、输入、输出以及状态。单个处理器可以被不同进程共享,进程调度算法决定不同进程工作的行止与顺序。一个程序运行两遍是两个进程。
2.1.2 进程创建
4个主要事件导致进程的创建
- 系统初始化
- 运行时的程序使用创建进程的系统调用
- 用户请求创建新进程
- 一个批处理作业的初始化(大型机系统认为有资源处理作业时就创建一个进程来处理)
所有情况中,都是一个已存在的进程执行系统调用创建进程。
父子进程之间的关系
父子进程有不同的地址空间,子进程的地址空间是父进程的副本(参数、代码都是一样的)其中不可写的内存区是共享的。
另一种描述:子进程共享父进程所有内存,只有对它们的内存写操作时才会复制一份(可写的内存不可共享)
2.1.3进程的终止
进程的终止条件
- 正常退出(自愿):系统调用
- 出错退出(自愿):出现错误后终止
- 严重错误(非自愿)直接被系统中断
- 被其他进程杀死(非自愿)主动kill
2.1.5进程的状态
- 运行态 (占用CPU)
- 就绪态(可运行,等待CPU)
- 阻塞态(需要外部事件,否则不能运行
supermemo/20211006115559.png · most-silence/PicGo - 码云 - 开源中国 (gitee.com)
2.1.6进程的实现
进程本身是一个抽象概念。支持它实现的抽象模型的是进程表process table。一个进程表项(进程控制块)代表一个进程。
什么是进程表项?
包含了进程状态的信息:程序计数器,堆栈指针,内存分配,打开文件的状态,调度信息,状态转换保存的信息。
中断向量interrupt vector的位置与I/O相关联,它包含了中断服务程序的入口地址。
举例:磁盘中断。
如果进程3在运行。中断硬件程序将程序计数器,程序状态字,寄存器信息压入堆栈,计算机跳转到中断向量指示的地址。由硬件完成。然后由中断服务例程接管剩余工作。
所有中断都有保存寄存器开始,该例程一般由汇编语言完成,可供所有中断程序使用(尽管中断引起的原因不同)。例程结束后调用C程序处理中断剩余工作。完成工作之后使下一个进程就绪,执行进程调度,载入寄存器值以及内存映射
中断发生后的底层实现:
- 硬件压入堆栈程序计数器等
- 硬件从中断向量装入新的程序计数器
- 汇编语言过程保存寄存器的值
- 汇编语言过程设置新的堆栈
- C中断服务例程运行
- 调度程序决定下一个进程
- C过程返回至汇编代码
- 汇编语言过程开始运行新的进程
2.2线程
每个进程有一个地址空间和一个控制线程而同一个地址空间允许运行多个线程(迷你进程)
2.2.1线程的使用
为什么要有线程?
- 在应用中需要同时发生多个活动,将这些应用分解成可以并行运行的多个顺序线程会使程序设计的模型更简单。
多线程模型:并行实体共享同一个地址空间和所有可用数据。 - 线程比进程更轻量级,更快地创建。
- 对于大量计算与IO处理,运行彼此重叠进行。
以组织Web服务器分析多线程的作用:
- 多线程:并行性阻塞系统调用
进程被分为三个线程,分别是:
分派程序线程从网络读入工作请求并检查请求。选择一个被阻塞的工作线程,唤醒它。
工作线程:处理请求,检查请求是否在高速缓存中,否则阻塞从磁盘调入。 - 单线程进程:无并行性,阻塞
循环:获得请求,检查请求,在下一个请求前完成整个工作。等待磁盘时,服务器 空转(阻塞)不处理其他请求 - 有限状态机:并行性,非阻塞,中断
在请求到来时检查,如果高速缓存中得到满足则正常运行,否则运行一个非阻塞的磁盘操作。服务器在表格记录当前请求的状态再去处理下一个事件。下一个事件可能是新的请求或者是磁盘对之前磁盘操作的返回(信号、中断的形式)。每次服务器改变请求工作的状态时,必须显示地保存或者重新装入相应的计算状态。
2.2.2线程模型
进程模型基于两种独立的概念:资源分组处理与执行
线程的独立性很小
线程之间没有保护:不可能也没必要。
线程模型中的内容:程序计数器 寄存器 堆栈 状态
进程模型中的内容:地址空间 全局变量 打开的文件 子进程 信号与信号处理等等。
2.2.4用户空间实现线程
第一种方法:整个线程包放在用户空间中,内核不可见,因此线程当作常规进程处理。
优点:
- 可以在不支持线程的操作系统上实现
- 进程内允许自定义对线程的调度算法。
每个进程都有一个专用的线程表。由运行时的系统管理。
装入所有线程的状态信息之后,进行线程的切换不需要陷入内核,速度快上一个数量级。
线程与进程一个关键差别:
线程完成运行时会把该线程信息保存在线程表中并进行线程切换,两者都是本地过程不需要陷入内核,不需要上下文切换,不需要内存高速缓存刷新。
用户级线程包的另一个问题是,如果一个线程开始运行,那么在该进程中的其他线程就不能运行,除非第一个线程自动放弃CPU。
一个