本文是进程管理中的第一部分,进程管理的内容是操作系统的核心,也是考试和面试的重点内容,本文将对进程与线程相关的内容进行梳理。
进程的概念及组成
对于进程的定义有很多,下面给出几种典型的定义:
- 进程是程序的一次运行过程。
- 进程是一个程序及其数据在处理机上顺序执行的活动。
- 进程是进程实体运行的过程,是系统进行资源分配和调度的独立单位。
进程主要由程序段、数据段和PCB(进程控制块)组成,其中PCB是进程存在的唯一标识。
PCB一般包括程序ID(PID)、特征信息(表示是系统进程、用户进程还是内核进程)、进程状态(就绪、阻塞或运行)、优先级、资源分配清单和处理机相关信息。程序段是能被调度的代码段。数据段可以是待处理的原始数据,也可以是中间数据或结果数据。
进程的状态与转换
进程主要有五种状态,分别是运行态、就绪态、阻塞态、创建态和结束态,其中前三种为进程的基本状态。
- 运行态。处理机运行进程时的状态,一般单处理机环境中,一个时刻最多只有一个进程在运行。
- 就绪态。就绪态是指进程等待处理机的状态,一旦得到处理机就立刻运行进程。
- 阻塞态。当进程交出处理机等待并使用资源(例如打印机)时的状态,此时即使处理机空闲也无法运行这个进程。
- 创建态。进程被创建但还没有转到就绪态时的状态。
- 结束态。进程需要结束,即将回收或释放资源时的状态。
![69b1538476df18532e146acd4c08ed85.png](https://i-blog.csdnimg.cn/blog_migrate/ead19a44657cfc9146678928741f3077.jpeg)
下面介绍一下三种基本状态的进程之间转换的情境。
- 就绪态->运行态:当就绪态的进程分配到时间片后,就会进入运行态。
- 运行态->就绪态:当运行态的时间片用完或者有更高优先级的进程就绪时,当前进程会让出处理机资源,进入就绪态。
- 运行态->阻塞态:当进程请求某一资源的使用或等待某一事件的到来,会从运行态转到阻塞态。
- 阻塞态->就绪态:当进程等到了请求的事件或使用完请求的资源(如打印机)时则会转为就绪态。
进程控制
进程的创建
进程可以创建另一个进程,创建者是父进程,被创建的进程是子进程。父进程为子进程提供资源。子进程运行结束后将资源还给父进程,父进程结束则所有子进程都会结束。
创建新进程的过程主要包括以下步骤:
- 为新进程分配一个进程识别号,并申请一个空白的PCB,若申请失败则创建新进程失败;
- 为新进程分配资源(内存空间),若分配失败则创建新进程失败;
- 初始化PCB,包括初始化标志信息、处理机状态信息和处理机控制信息,并设置进程优先级;
- 若就绪队列可以插入新进程就将新进程插入就绪队列。
进程的终止
进程终止的过程主要包括以下步骤:
- 根据进程标识符检索PCB并读取进程的状态;
- 若进程处于运行状态则终止进程并将处理机资源分配给其他进程;
- 若当前进程有子进程则终止子进程;
- 将当前进程拥有的全部资源还给父进程或操作系统;
- 将该进程的PCB从队列中删除。
进程的阻塞和唤醒
进程阻塞是进程的一种主动行为,主要在等待某一事件完成、新数据尚未到达或无工作可做时发生。进程阻塞需执行阻塞原语,主动让出处理机,因此只有运行态可以转换成阻塞态。阻塞原语的执行过程如下:
- 找到要被阻塞的进程的PCB;
- 为运行态的进程保护现场并将状态转为阻塞态,让出处理机资源;
- 将PCB插入相关事件的等待队列。
进程的唤醒是一种被动行为,一般是进程期待的数据到达或事件完成后发生。进程的唤醒原语执行过程如下:
- 在等待队列找到被唤醒的进程的PCB;
- 将该PCB移出并将其状态置为就绪态;
- 将PCB插入就绪队列,等待处理机调度该进程。
进程的切换
进程间的切换往往在内核态下发生,主要过程包括:
- 保存处理机上下文,包括程序计数器和其他寄存器;
- 更新PCB信息;
- 将PCB移入就绪队列或阻塞队列;
- 切换到另一个进程运行,并更新其PCB;
- 更新内存管理的数据结构;
- 恢复处理机上下文。
进程通信
进程间通信主要有三种方式:共享存储、消息传递和管道通信。
共享存储
![cc879da21e7a3517892db47f990614f5.png](https://i-blog.csdnimg.cn/blog_migrate/4d0f1ad0af3ea561b2d4bc46c82d092b.png)
共享存储的原理很简单,就是一个进程将需要通信的数据放在共享空间里,另一个进程来共享空间中取出数据即可。
消息传递
消息传递系统是当今使用最广泛的进程通信方式,进程间的数据交换是以格式化的消息(message)为单位的。根据实现方式的不同,消息传递又可分为直接通信方式和间接通信方式。
直接通信方式是指发送进程直接将数据发送给接收进程,数据被插入接收进程的消息缓存队列中,接收进程从缓冲队列取出消息使用。
![6dab3f81071a9514d59697f01ffc332b.png](https://i-blog.csdnimg.cn/blog_migrate/282d2c56bf5288eb6247423d3cdefa44.png)
间接通信方式是指发送进程将消息发送到一个中间实体中,接收进程从中间实体取出消息并使用,这里的中间实体被称为信箱。间接通信方式的原理和消息队列(如RabbitMQ、RocketMQ、Kafka等)的原理一致,与直接通信方式相比,降低了进程间的耦合度。
![443ae0b9b09f338ab4d388659edac9f5.png](https://i-blog.csdnimg.cn/blog_migrate/465f6d86d9bc7b37b9496fcbfbcdd0f9.png)
管道通信
学习过Java NIO的同学应该对管道不陌生,管道就是用于连接一个读进程和一个写进程进行通信的一个共享文件,又名pipe文件。值得注意的是,管道中的数据都是一次性的数据,一旦被读进程使用过就管道就会将这部分数据丢弃。
![476d3dd1f90cbbb56ad67ead388d71c2.png](https://i-blog.csdnimg.cn/blog_migrate/b1ca414bbc6422ff4daca4103723ce73.png)
线程
进程和线程的比较
线程可以被理解为“轻量级的进程”,提高了资源利用率和吞吐量,加大了系统并发能力。我们从下面几个角度来对比一下进程和线程之间的差异。
- 调度。在传统操作系统中,进程是拥有资源的基本单位和独立调度、分派的基本单位。在引入线程的操作系统中,线程成为了调度和分派的基本单位,而进程是拥有资源的基本单位。同一进程中的线程的切换不会引起进程的切换,而不同进程的线程切换则会引起进程切换。
- 并发性。在引入线程的操作系统中,不仅进程可以并发执行,线程也可以并发执行,从而可以提高线程的吞吐量。
- 拥有资源。进程是拥有资源的基本单位,线程除了一些必须的资源外不拥有资源,但是线程可以使用所在进程的资源。
- 系统开销。系统开销方面,毫无疑问,进程一定比线程开销大。在创建和撤销进程时,系统需要为进程分配和回收资源;在进程切换时,进程需要保存当前进程的CPU环境,设置被调度进程的CPU环境。线程的切换开销则小了很多,只需要设置保存少量寄存器中的内容即可。Java中线程切换时,Java虚拟机会保存程序计数器中的内容。
线程的实现方式
线程的实现主要分为用户级线程和内核级线程。用户级线程是由用户创建的线程,内核意识不到用户级线程的存在;内核级线程的管理由内核完成,内核为进程及其内部的线程维护上下文信息,调度也在内核基于线程架构的基础上上完成的。
多线程模型
多线程模型是用户级线程和内核级线程结合的模型,一般有以下几种多线程模型:
- 一对一模型。一对一模型将一个用户级线程映射到一个内核级线程中。优点是一个线程阻塞后,另一个线程可以继续执行,并发能力强。缺点是每个用户级线程都需要对应一个内核级线程,开销太大。
- 多对一模型。多个用户级线程对应一个内核级线程。优点是线程在用户空间管理,效率较高。缺点是一个线程使用内核服务时阻塞会导致整个进程阻塞。
- 多对多模型。多个用户级线程对应多个内核级线程,内核级线程数不大于用户级线程数。该模型集合了前两种方式的优点。
欢迎点赞关注我的微信公众号:SKY技术修炼指南