进程概述
进程概念
进程定义
定义:
处于 ==并发== 状态下
具有某种功能的程序在某个数据集上执行的 ==过程==
是 ==进程调度== 和 ==资源分配== 的 ==独立== 单位
进程 & 程序
进程是 ==活动== 的实体:进程 = 程序段 + 数据段 + 进程控制块
程序是 ==被动== 的实体:只是存放在硬盘中的代码段
分类:
- CPU 密集型进程 & I/O 密集型进程
- 独立进程 & 协作进程
- 前端进程 & 后端进程
- 父进程 & 子进程
- 孤儿进程 & 僵尸进程 & 守护进程
细节:
处理器频繁切换进程实现并行;采用跟踪正在运行的进程集(主存)而不是跟踪处理器如何切换的
并行 & 伪并行
并行:多个进程 ==同时== 运行
伪并行:处理器通过频繁 ==切换== 进程执行
解释:制造了多个进程同时进行的错觉
1. 单处理器系统每个瞬间只能够运行一个进程 -> 单处理器系统并没有实现真正意义上的并行(伪并行)
2. 多处理器系统具有多个处理器芯片每个瞬间可以运行多个进程 -> 多处理器系统实现了真正意义上的并行
解释:同一个程序可以被执行多次,每执行一次都算作一个进程,但是程序只有一个
进程状态
五种状态
初始态(
new
):进程刚被创建时的状态- 创建的情况:(1)系统初始化;(2)正在执行进程创建另一个进程;(3)用户请求创建新的进程
就绪态(
ready
):进程已经获取到所需所有资源;等待处理器的调度后即可执行运行态(
running
):处理器中正在执行的进程阻塞态(等待态)(
wating
):进程等待某些资源的获取终止态(
terminated
):进程执行完成- 终止的情况:(1) 正常退出;(2) 出错退出;(3)被其他进程杀死
状态转换图:
进程控制块
定义:每个进程都维护的一个结构数组,用于保存进程所有的相关信息
相关信息:(进程相关的所有信息都存放在进程控制块中:可能是具体的数据也可能是指针)
进程描述信息 进程控制信息和管理信息 资源分配信息 处理器相关信息 进程唯一标识符 进程状态 代码段指针 程序状态字寄存器 用户唯一标识符 进程优先级 数据段指针 地址寄存器 子进程 & 父进程唯一标识符 代码段入口地址 堆栈段指针 程序计数器 程序磁盘地址 文件描述符 通用寄存器 进入内存时间 & 处理器使用时间 外接设备 信号量 上下文:当前进程的物理实体(PCB)和进程的运行环境(处理器各个寄存器值)被统称为上下文
- 上下文切换:保存当前正在执行的进程状态(运行环境)然后载入另一个进程的状态(运行环境)
- 具体过程
- 保存当前 处理器的各个寄存器的值 并且 更新 进程相应的 进程控制块信息
- 载入 将要运行的进程的 进程控制块 并且 更新处理器各个寄存器的值
进程调度
定义:多个进程需要处理器执行,调度程序采用一定的 ==策略== 选择其中一个进程分派给处理器执行
调度队列:
作业队列:包含操作系统中的所有初始态的进程(未分配到相应资源的进程)
就绪队列:已经加载到内存中等待执行的进程
设备队列:包含所有需要相应 I/O 资源的进程
调度程序:
定义:将处理器的 ==控制权== 交付 给由调度算法确定的 ==进程==
功能:
- 上下文切换(保存当前进程时会从用户态进入内核态;恢复新进程时会从内核态进入用户态)
- 获取 PCB 中程序计数器的值跳转到合适的位置 -> 重新执行进程
CPU 密集型进程 & I/O 密集型进程
CPU 密集型进程:需要花费更多时间在执行计算上
I/O 密集型进程:需要花费更多时间在提交 I/O 请求上
调度延迟:调度程序保存一个进程并恢复另一个进程的过程(上下文切换)所花费的时间
调度程序分类
长期调度程序:从硬盘等二级存储中调度 ==程序== 到 ==内存== 中等待执行
短期调度程序:从内存中调度 ==进程== 到 处理器中执行 (这只是一种抽象的说法:实际上是处理器获取到进程的入口地址和寄存器信息开始执行进程)
中期调度程序:将 ==进程== 从内存中 ==暂时交换== 到备份存储的 ==交换空间== 中,从而降低多道程序系统的度,在合适的时候再将进程调入内存中继续执行
交换方式:
标准交换:将进程再次调度进入内存时分配进程 ==可能需要== 的内存大小
“变体”交换:将进程再次调度进入内存时分配进程 ==真正需要== 的内存大小(进程可以利用系统调用告知操作系统)
备份存储:通常是大容量的存储设备(磁盘)
原因:长期调度程序在调度进程时很可能对于进程的组合不够得当,导致 CPU 或 I/O 的效率很低 -> 借助中期调度程序进行改善
优点 & 缺点:
细节:
中期调度程序在 ==换出进程== 时应该确保进程中的那个进程是 ==完全空闲== 的
解释:如果进程处于设备等待队列,那么就是不能够立即换出的
-
解释:Android & iOS 在空闲内存低于阈值时都是要求进程 ==主动放弃== 占用的内存以达到释放内存的目的
调度队列图
进程调度 & 上下文切换的区别
- 进程调度仅仅只是 决定将要分配 给进程何种资源何种环境 (决策行为)
- 上下文切换是 真正意义 上将资源和环境分配给进程 (执行行为)
进程实现
前提:按照 UNIX 标准实现进程;Windows 实现类似
进程层次结构:
父进程 & 子进程:
- 父进程:创建子进程的进程
- 子进程:由父进程调用
fork()
函数创建的进程
进程组:父进程和其派生的 ==所有== 子进程共同组成进程组
进程标识符(PID):每个进程由操作系统分配的 ==唯一== 编号
资源共享:
- 父进程允许子进程共享 ==全部== 资源
- 父进程不允许子进程共享资源 -> 子进程只可以从 ==操作系统== 处获取资源
- 父进程允许子进程共享 ==部分== 资源
运行顺序:
父进程可以和子进程并发运行;父进程和子进程此时都进入就绪队列 -> 处于就绪态
父进程等待子进程执行结束后再执行;只有子进程进入就绪队列,处于就绪态;父进程直到子进程结束之前都处于阻塞态
细节:
UNIX Solaris 中进程都是采用 ==树形== 层次结构;Windows 中并没有进程层次的概念,所有进程都是平等的
每个子进程可以继续创建自己的子进程
父进程和子进程的 逻辑地址 和 物理地址 都是相同的(在调用
exec
指令或者进行写操作之前)解释:需要使用写时复制进行解释
进程实现方式
进程创建:
fork()
创建过程:
父进程调用
fork()
函数创建自身的 ==副本进程==(子进程) ->fork()
函数返回子进程的进程标识符操作系统创建 空白进程控制块 (如果进程控制块创建失败则会直接导致 进程创建失败)
操作系统为进程分配内存空间 (如果内存空间不足以容纳新的进程则会导致 进程处于阻塞态)
操作系统 初始化进程控制块信息
调度程序将子进程调度进入就绪队列等待执行
子进程可以调用
exec()
函数载入新的程序运行
解释:子进程不再是父进程的副本,调用 `fork()` 也可以创建子进程了
写时复制:
引入:
父进程在调用
fork()
函数时会创建副本子进程;显然需要将父进程的所有内容全部复制一遍但是大多数的子进程在被创建后都会立刻执行
exec()
函数去执行另一个程序;这样就显得此前复制操作非常没有必要概念:
子进程在被创建后和父进程共享同一块内存空间
等待子进程需要对内存空间进行 ==写操作== 时才单独为子进程分配单独的内存空间并复制父进程的内容
细节:
子进程写操作
- 子进程不使用
exec()
进行写操作:操作系统仍然会让子进程和父进程共享代码段;其余内容重新分配 - 子进程使用
exrc()
进行写操作:操作系统会对子进程的所有内容重新分配
- 子进程不使用
进程等待:
wait()
- 父进程创建子进程之后选择等待子进程执行结束后再执行就会使用
wait()
指令
- 父进程创建子进程之后选择等待子进程执行结束后再执行就会使用
进程删除:
exit()
&kill()
正常退出:进程使用
exit()
指令即可退出;子进程退出后exit()
指令返回 ==退出状态==异常退出:进程出现访问越界,使用非法指令,运行超时,运算出错等都会造成进程异常结束 (子进程使用了不该使用的资源)
外界干预:父进程被终止或者程序员手动干预
终止过程:
- 操作系统根据 进程唯一标识符 查找其 进程控制块 (进程控制块最后删除)
- 操作系统 终止 该进程的 所有子进程 并且将其拥有的资源全部 还给父进程或操作系统
- 操作系统在在 链表 中 删除 该进程的 进程控制块
细节:
父进程调用 fork() 函数会得到子进程的进程标识符;子进程如果仍然是副本的话调用 fork() 函数只会得到 0
解释:因为子进程也是从
fork()
函数开始执行的,如果子进程也正常调用fork()
函数创建子进程,那就成死循环了fork()
函数时 UNIX 中 ==唯一== 可以创建进程的函数exec()
并不是一个具体的函数而是包含了execl
execv
execle
execve
execlp
execvp
六种具体函数Windows 进程相关函数:
- CreateProcess = fork + exec
- ExitProcess = exit;TerminateProcess = kill
|
进程协作 & 通信
协作进程 & 独立进程
协作进程:能够 ==影响== 其他进程或者 ==受== 其他进程 ==影响== 的进程
注:提供相应的环境保证多个进程之间可以协作通信显然更有利于用户
独立进程:不能够影响其他进程也不受其他啊进程影响的进程
进程通信机制(IPC)
共享内存:
定义:允许两个或多个通信进程访问同一块物理内存
优点:共享内存的通信方式 ==效率更高==
解释:只有在创建共享内存区域的时候需要使用系统调用,进程访问共享区域都是 ==直接访问== 的,不需要使用系统调用
缺点:共享内存没有提供进程同步机制 -> 同步机制
解释:共享区域有进程正在使用时,其他进程不需要等待当前进程结束就可以使用共享区域,即共享区域没有上锁
注:共享内存不代表进程之间可以相互访问对方的内存空间,本质上访问的是共享区域
消息传递
定义:两个或多个进程之间通过发送规定格式的消息进行通信
优点:分布式系统/多核处理器中中采用消息传递的方式效率相对更高且容易实现
注:共享内存在这种情况下会出现高速缓存不一致的情况
缺点:消息传递的通信方式 ==效率更低==
解释:进程每次发送消息都需要执行系统调用,需要和内核交互,导致执行效率较低
优点:(1) 信息共享;(2)计算加速;(3)模块化;(4) 更加便利
生产者-消费者
生产者 & 缓冲区 & 消费者
生产者:生成数据信息的进程
消费者:使用数据信息的进程
缓冲区:用于存储生产者生成的数据信息,并且提供给消费者使用数据信息的区域
过程:
生产者进程生成数据信息提交至缓冲区中
消费者进程从缓冲区中获取数据信息
细节
- 生产者-消费者模式不是 23 种设计模式中的;23 种设计模式都是基于面向对象的,该模式是基于面向过程的
- 生产者-消费者模式时采用共享内存实现的;缓冲区就是两者共享的内存
实现(循环队列)