操作系统——进程管理
进程与线程
1.进程
概念:资源分配的基本单位
进程控制块(PCB):描述进程的基本信息和运行状态,所谓的创建进程和撤销进程,都是指对 PCB 的操作
2.线程
概念:独立调度的基本单位
关系:一个进程可以有多个线程,共享进程资源
举例:Wechat和抖音是两个进程,Wechat进程中有多个线程,如事件响应线程,渲染线程等,线程的并发执行使用户在使用Wechat时在渲染页面时,还可以响应用户的其他事件。
3.区别
进程 | 线程 | |
---|---|---|
拥有资源 | 资源分配的基本单位 | 不拥有资源,但可以访问隶属进程的资源 |
调度 | 在同一进程中,线程的切换不会引起进程切换,从一个进程中的线程切换到另一个进程中的线程时,会引起进程切换 | 独立调度的基本单位 |
系统开销 | 进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置 ,开销大 | 线程切换时只需保存和设置少量寄存器内容,开销很小 |
通信方面 | 进程通信需要借助 IPC | 线程间可以通过直接读写同一进程中的数据进行通信 |
进程状态切换
- 只有就绪态和运行态可以相互转换,其它的都是单向转换。就绪状态的进程通过调度算法从而获得 CPU 时间,转为运行状态;而运行状态的进程,在分配给它的 CPU 时间片用完之后就会转为就绪状态,等待下一次调度
- 阻塞状态是缺少需要的资源从而由运行状态转换而来,但是该资源不包括 CPU 时间,缺少 CPU 时间会从运行态转换为就绪态。
进程调度算法
- 批处理系统
调度算法目标:保证吞吐量和周转时间(从提交到终止的时间)
先来先服务 first-come first-serverd(FCFS) | 短作业优先 shortest job first(SJF) | 最短剩余时间优先 shortest remaining time next(SRTN) |
---|---|---|
非抢占式 | 非抢占式 | 短作业优先的抢占式 |
按照请求的顺序进行调度 | 按估计运行时间最短的顺序进行调度 | 按剩余运行时间的顺序进行调度 |
有利于长作业,但不利于短作业,因为短作业必须一直等待前面的长作业执行完毕才能执行,而长作业又需要执行很长时间,造成了短作业等待时间过长 | 长作业有可能会饿死,处于一直等待短作业执行完毕的状态。因为如果一直有短作业到来,那么长作业永远得不到调度 | 当一个新的作业到达时,其整个运行时间与当前进程的剩余时间作比较。如果新的进程需要的时间更少,则挂起当前进程,运行新的进程;否则新的进程等待 |
- 交互式系统
调度算法的目标:快速地进行响应
2.1 时间片轮转
将就绪进程按FCFS排成队列,调度时,将CPU时间分给队首进程执行一个时间片,用完后,计时器发出时钟中断,调度程序停止该进程并将其调至队列末尾,继续分配CPU时间。
效率与时间片大小相关:进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间;而如果时间片过长,那么实时性就不能得到保证
2.2 优先级调度
每个经常都有优先级,按优先级调度,可随时间的推移增加进程的优先级
2.3 多级反馈队列
多级队列的每个队列时间不同,为需要连续执行多个时间片的进程考虑,当进程在第一个队列没执行完时,会被移到下一个队列。
每个队列优先权也不同,最上面优先权最高,故只有上一个队列没有进程在排队,才可调度当前队列上的进程。 - 实时系统
实时系统要求一个请求在一个确定时间内得到响应。
分为硬实时和软实时,前者必须满足绝对的截止时间,后者可以容忍一定的超时
进程同步
基本概念:临界区、临界资源、同步和互斥、信号量、管程
在多道程序环境下,进程是并发执行的,不同进程之间存在着不同的相互制约关系。为了协调进程之间的相互制约关系,引入了进程同步的概念
临界区:对临界资源进行访问的那段代码称为临界区。为了互斥访问临界资源,每个进程在进入临界区之前,需要先进行检查,分为四部分:
do {
entry section; //进入区
critical section; //临界区
exit section; //退出区
remainder section; //剩余区
} while (true)
临界资源:
一次仅允许一个进程使用的资源称为临界资源
同步和互斥:
- 同步:多个进程因为合作产生的直接制约关系,使得进程有一定的先后执行关系。
- 互斥:多个进程在同一时刻只有一个进程能进入临界区
信号量:
信号量(Semaphore)是一个整型变量,可以对其执行 down 和 up 操作,也就是常见的 P 和 V 操作
- down : 如果信号量大于 0 ,执行 -1 操作;如果信号量等于 0,进程睡眠,等待信号量大于 0;
- up :对信号量执行 +1 操作,唤醒睡眠的进程让其完成 down 操作。
如果信号量的取值只能为 0 或者 1,那么就成为了 互斥量(Mutex) ,0 表示临界区已经加锁,1 表示临界区解锁
typedef int semaphore;
semaphore mutex = 1;
void P1() {
down(&mutex);
// 临界区
up(&mutex);
}
void P2() {
down(&mutex);
// 临界区
up(&mutex);
}
管程:
管程是由一组数据以及定义在这组数据之上的对这组数据的操作组成的软件模块。
在一个时刻只能有一个进程使用管程。进程在无法继续执行的时候不能一直占用管程,否则其它进程永远不能使用管程
管程引入了条件变量以及相关的操作:wait() 和 signal() 来实现同步操作。对条件变量执行 wait() 操作会导致调用进程阻塞,把管程让出来给另一个进程持有。signal() 操作用于唤醒被阻塞的进程
进程同步经典问题
三个经典问题用Java详解
生产者消费者的实现
Java多种方式解决生产者消费者问题(十分详细)
进程通信
与进程同步的区别:
- 进程同步:控制多个进程按一定顺序执行;
- 进程通信:进程间传输信息
管道
管道是通过调用 pipe 函数创建的,
fd[0] 用于读,fd[1] 用于写。
#include <unistd.h>
int pipe(int fd[2]);
限制:
- 只支持半双工通信(单向交替传输);
- 只能在父子进程或者兄弟进程中使用。
FIFO
概念:命名管道,去除管道只能在父子进程中使用的限制
#include <sys/stat.h>
int mkfifo(const char *path, mode_t mode);
int mkfifoat(int fd, const char *path, mode_t mode);
FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据
消息队列
相比于 FIFO,消息队列具有以下优点:
- 消息队列可以独立于读写进程存在,从而避免了 FIFO 中同步管道的打开和关闭时可能产生的困难;
- 避免了 FIFO的同步阻塞问题,不需要进程自己提供同步方法;
- 读进程可以根据消息类型有选择地接收消息,而不像 FIFO 那样只能默认地接收。
信号量
它是一个计数器,用于为多个进程提供对共享数据对象的访问。
共享存储
允许多个进程共享一个给定的存储区。因为数据不需要在进程之间复制,所以这是最快的一种 IPC。
需要使用信号量用来同步对共享存储的访问。
多个进程可以将同一个文件映射到它们的地址空间从而实现共享内存。另外 XSI 共享内存不是使用文件,而是使用内存的匿名段。
套接字
与其它通信机制不同的是,它可用于不同机器间的进程通信。
参考资料:
https://cyc2018.github.io/CS-Notes/#/notes/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%20-%20%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86
https://blog.csdn.net/ldx19980108/article/details/81707751