2023-06-11
原文作者:奇小葩 原文地址:https://blog.csdn.net/u012489236/category_10946851.html

对于内存管理告一段落,今天正式开始进入内存管理的章节,首先从基础学习,主要是包括进程线程基础概念篇,主要包括以下内容

  • 为什么要引入进程的概念
  • 进程的概念,进程和程序的联系和区别
  • 进程控制块
  • 进程的状态模型

1. 为什么要引入进程

早期的计算机一次只能执行一个任务,采用批处理的方法,由监督系统完成作业的切换,使得作业一个接一个的被处理,如下图所示

202306111302446041.png

  • 首先,由监督器将磁带上的第一个程序装入内存,并把运行的控制权交给作业
  • 当该作业批处理完成时,又把控制权交还给监督程序,再由监督程序把磁带上的第二个作业调入内存,计算机系统就这样自动地一个任务有一个任务的进行处理,直到将磁带上的所有作业全部完成

对于该批处理系统内存中仅有一道程序运行,即每次监督器只能从磁带上调入一道程序进入内存中运行,当该程序完成或发生异常时,才换入其他后续程序进入内存运行,这就是早期的批处理系统。但是随着计算机的发展趋势,这种已经不能满足越来越复杂的场景需求

  • 计算机程序种类越来越多(文本编辑、科学计算、web服务…)
  • 外部设备种类越来越多(磁盘、显示、网络),造成程序等待

就会出现以下的情况

202306111302475582.png

我们以实际的例子,来说明这种情况下的弊端

202306111302485473.png

对于上面的程序A和程序B,如果在单道程序设计中,需要80个时间周期才能执行完,而采用多道程序设计,A程序等待的时候,B程序可以调度执行,相同的操作只需要45个时间周期就能完成,其效率如下所示

单道程序 多道程序
CPU利用率 40/80=50% 40/45=89%
DEV1利用率 15/80=18.75% 15/45=33%
DEV2利用率 25/80=31.25% 25/45=56%

所以,对于这种批处理系统, 每次上机时, 我和其他程序都排好队, 一个接一个的进入内存运行。但是这种效率低下,为了创建和谐社会,促进效率和公平, 充分发挥每一个人的能力,所以就引入了多道程序设计的概念。

主要是为了提高CPU利用率,人们设计了在一台计算机实现能将多个程序同时加载、并发执行,从而引入进程的概念。

  • 每个加载到内存中的程序都称为进程,操作系统管理者多个进程并发执行。
  • 进程会认为自己独立占用CPU资源

2. 进程的概念

2.1 进程的定义

进程是指一个具有一定 独立功能的程序 在一个 数据集合 上的一次 动态执行过程 。其如下图所示

202306111302492654.png

由上图可以知道,进程包含了正在运行的一个程序的 所有的状态的信息 ,其主要包括以下

  • 代码
  • 数据
  • 状态寄存器,例如CPU的状态,栈指针,PC指针等
  • 通用寄存器
  • 进程占用系统资源,打开文件,已分配的内存信息等

2.2 进程的特点

  1. 动态性

    • 可以动态创建、结束进程
  2. 并发性

    • 进程可以被独立调度并占用处理器运行
  3. 独立性

    • 不同进程的工作不相互影响
  4. 制约性

    • 因访问共享数据/资源或进程间同步而产生制约

      202306111302514915.png

2.3 进程与程序的联系

  1. 进程是操作系统处于执行状态程序的抽象

    • 程序 = 文件 (静态的可执行文件)
    • 进程 = 执行中的程序 = 程序 + 执行状态
  2. 同一程序的多次执行过程对应为不同的进程

    • 如命令ls的多次执行对应多个进程
  3. 进程执行是需要资源

    • 内存:保护代码和数据
    • CPU:执行指令

2.4 进程与程序的区别

  1. 进程是动态的,程序是静态的

    • 程序是有序代码的集合
    • 进程是程序的执行,进程有核心态和用户态
  2. 进程是暂时的,程序是永久的

    • 进程是一个状态变化的过程
    • 程序可长久保存
  3. 进程与程序的组成不同

    • 进程的组成包括程序、数据和进程控制块

3. 进程控制块(PCB)

进程是操作系统中调度的一个实体,需要对进程所拥有的资源进行抽象,这个抽象的形式就是进程控制块(PCB),主要是用来管理控制进程运行所用的信息集合。

  • 操作系统用PCB来描述进程的基本情况以及运行变化的过程
  • PCB是进程存在的唯一标志,每个进程都在操作系统中一个对应的PCB

对于进程控制块需要描述以下信息

  • 进程的运行状态:包括就绪、运行、等待阻塞、僵尸等状态
  • 程序计数器:记录当前进程运行到哪条指令
  • CPU寄存器:主要用于保存当前运行的上下文,记录CPU所有必须保存下来的寄存器信息,以便当前进程调度出去之后还能调度回来并接着运行
  • CPU调度信息:包括进程优先级、调度队列和调度等相关信息
  • 内存管理信息:进程使用的内存信息,如进程的页表等
  • 统计信息:包含进程运行时间等相关统计信息
  • 文件相关信息:包括进程打开的文件等

因此,进程描述符是用于描述进程运行状态以及控制进程运行所需要的全部信息,是操作系统用来感知进程存在的一个非常重要的额数据结构。任何一个操作系统的实现都需要一个数据结构来描述进程描述符,所以linux内核采用一个名为task_struct的结构体,该内容后面详细学习。

对于进程的上下文切换,如下图所示

  • 进程主要是通过中断或者系统调用进入内核
  • 上下文保存在对应的PCB中,被调度时,从PCB取出上下文并恢复进程

202306111302546556.png

4. 进程的生命周期

一个进程的生命周期可以划分为一组状态,这些状态刻画了整个进程。进程状态即体现一个进程的生命状态。进程的整个生命周期如下

202306111302552837.png

4.1 进程创建

在linux系统中,许多进程在诞生之初都与其父进程共同用一个存储空间。但是子进程又可以建立自己的存储空间,并与父进程“分道扬镳”,成为与父进程一样真正意义上的进程。

linux系统运行的第一个进程是在初始化阶段“捏造出来的”。而此后的线程或进程都是由一个已存在的进程像细胞分裂一样通过系统调用复制出来的,称为“fork()”或者“clone()”引起进程创建的情况

  • 系统初始化创建,例如第一个进程
  • 用户请求创建一个新进程
  • 正常运行的进程执行创建进程的系统调用

4.2 进程执行

进程的创建解决了从无到有的过程,而当进程创建后,就处于就绪状态,进程具备运行条件,等待系统分配处理器以便运行。

而进程的执行是内核选择一个就绪的进程,让它占用处理器并执行,主要是从就绪状态切换到运行态的过程,但是这里面涉及到如何选择哪个就绪队列,采用何种算法,这个后面会单独学习

4.3 进程等待

指进程不具备运行条件,正在等待某个事件的完成,此时进程进入等待(阻塞)的状态,其有如下情况

  • 请求并等待系统服务,无法马上完成
  • 启动某些操作,无法马上完成
  • 需要的数据没有到达

只有进程自身才知道何时需要等待某种事情的发生,该过程只能发生在运行态到等待态的。

4.4 进程抢占

进程抢占可能发生在两种情况下:

  • 更高优先级的任务进入TASK_RUNNING状态
  • 当前进程的时间片到期

无论进程当前运行在内核态还是用户态,都可以发生抢占,被抢占的进程仍然运行在TASK_RUNNING状态。

4.5 进程唤醒

唤醒进程的情况

  • 被阻塞进程需要的资源可以满足
  • 被阻塞进程等待的事件到达

进程只能被别的进程或操作系统唤醒

4.6 进程结束

进程结束的情况

  • 正常退出(自愿的)
  • 错误退出(自愿的)
  • 致命错误退出(强制性的)
  • 被其他进程所杀(强制性的)

我们来看看sleep系统调用对应的进程状态的变化情况,如下图

202306111302577528.png

  • 首先,创建sleep进程,进程处于就绪状态,等待操作系统调度
  • 当操作系统从就绪态开始执行该进程,就处于运行态
  • 运行态去等待time硬件时间到,系统马上就切换到等待态,并切换到另外的进程运行
  • 当硬件时间到后,该进程马上就回到就绪,等待操作系统运行
  • 当再次运行完毕后,该进程就退出

我们来实现看看进程切换的完成状态图,如下图示

202306111302590899.png

5. 进程的状态模型

2023061113030028910.png

  • 启动: 从NULL->创建的过程,一个新进程被产生出来执行一个程序
  • 创建->就绪: 当进程被创建完成并初始化后,一切就绪准备运行时,就变成就绪状态
  • 就绪->运行: 处于就绪状态的进程被进程调度程序选中后,就分配到处理机上来运行
  • 运行->结束: 当进程表示它已经完成或者因某种原因出错,当前运行进程会由操作系统结束处理
  • 运行->就绪: 处于运行状态的进程在其运行过程中,由于分配给它的处理机时间片用完而让出处理机
  • 运行->等待: 当进程请求某资源且必须等待
  • 等待->就绪: 当进程要等待某事件到来时,它从阻塞状态变成就绪状态

6. 进程挂起模型

每次执行中的进程必须完全载入内存中,因此所以队列中的所有进程必须驻留在内存中。内存中保存多个进程,当一个进程正在等待,处理器可以转移到另外一个进程,但是CPU比I/O要快很多,以至于内存中所有进程都在等待I/O的情况就显得很常见。那么我们该如何处理这种问题呢?

  • 该问题产生的直接原因是内存问题,那么最直接的方法是扩充内存适应更多的进程
  • 另外一种方式,是虚拟内存技术的方式,采用交换,把内存中某个进程的一部分或者全部移到磁盘中。当内存中没有处于就绪状态的进程时,操作系统就把阻塞的进程换到磁盘中的“挂起队列”中。

2023061113030180211.png

不同于进程阻塞。挂起时没有占用该内存空间,而是映像在磁盘上,主要是减小进程占用内存。类似虚存中,有的程序段被放到了硬盘上。

  • 等待挂起状态:该状态是由等待状态切换,进程在外出中并等待某事件的出现
  • 就绪挂起状态:进程在外存中,但只要进入内存,即可运行

7. 总结

本章主要是学习了操作系统为何要引入进程这个概念,为了提高CPU利用率。多批道处理系统一次性载入多个作业到内存中让程序并发执行,但这会造成一系列的问题,引入进程这些问题得以解决,同时也学习了进程的相关的概念。但是随着人们需求越来越多,对于并发的要求越来越高,单纯的进程已经不能满足于日常的需求,此时就导致线程的概念的产生。

阅读全文