操作系统(2)进程管理(上)进程与线程

2.1.概述

2.2.CPU的管理

CPU本质上就是一个去内存中根据地址取指令,然后执行指令的硬件。CPU的完整取址执行流程如下:
CPU要执行的指令的地址存在寄存器中,指令存放在内存中。
例如PC寄存器中存放50,CPU读到存放的50,发出一条取址指令,经由地址总线去取出地址为50的内存单元中的指令。最后CPU解释执行该指令,CPU工作的过程就是不断的取址执行。
在这里插入图片描述
整个过程中存在几个问题:

  • CPU的利用率不高
  • 缺少控制

CPU利用率不高:

如果某段程序需要频繁的与IO进行交互,由于IO操作要涉及外设硬件的一些机械性的动作,明显IO的速度低于CPU速度几个量级,CPU需要等到IO的结果,等待过程中CPU的时间片资源就被浪费掉了。并且这个等待过程是无法跳过的,因为当前程序的后续指令很可能要依赖于此次IO的结果,没法先不等IO的结果而继续执行当前程序后续的指令。

缺少控制:

程序之间存在轻重缓急,比如当前CPU正在运行一个打印文件的程序指令,由于要和IO设备打交道,这个程序是比较耗时间的。此时进来了一条发射核弹的程序指令,明显优先级高的程序等到优先级低的程序执行完毕,而且前一条指令合适执行完毕,完全无从得知。

解决问题的思路:

CPU的空闲时间去做其他事儿。
那么怎么实现喃?这样去做,不让程序一口气执行完,而是将CPU的时间分成时间片,这一秒属于程序A,下一秒属于程序B,下一秒又属于程序A…让程序交替的去执行,这样的话即使遇到了诸如IO这种耗时操作也能利用其期间的空闲时间。比如一个IO操作本来要三秒,也就是说CPU从执行这个IO操作开始要苦等三秒钟才能能到返回结果,但是时间分片、程序交叉执行后,假设时间片分成了一秒一个,这一秒遇见了IO,下一秒分给了其他程序,下一秒再回来,这样中间的时间就被利用起来了。
CPU时间分片、程序交叉执行后,有一个问题是要解决的:
由于是多个程序交叉运行,所以总的体感上一定是多个程序在”并发“的执行,也就是说同时有多个程序在运行,那么要对这些程序切来切去就一定要对这些运行的程序进行描述,要描述某个程序执行到了何处之类的消息。这样来回调度的时候才能接着上次继续运行。当然对线程的描述肯定不止一个上次运行到哪里这一个内容还有很多细节的内容,比如可以给每个运行中的程序一个优先级,优先级大的多分点时间片给它,也需要给每个运行中的程序一个编号好进行区分。注入此类的一堆的对运行中的程序的描述叫做——进程。

2.2.进程

2.3.1.进程的概念

操作系统的核心功能是管理硬件,而CPU是计算机的核心硬件,而CPU的核心功能是运行程序,为了保证CPU在运行程序时资源得到充分的利用,所以会在运行的程序间切来切去,这种切换之间自然需要一种结构来描述运行中的程序,记录一些必须要记录的信息(比如上次执行到了哪里?),于是引入了进程的概念。

进程:

用于描述和管理程序的“运行过程”。是指程序在某个数据集合上的一次运行活动。是分配资源的一个基本单位

数据集合:

软/硬件环境。

进程的特性:

  • 动态性
  • 并发性
  • 异步性
  • 独立性

​动态性:
进程是程序的一次执行过程,动态的产生、消亡。
并发性:
就单CPU而言,多个进程在宏观上是并发的,但实际上只是分时上时间片足够小实现的伪并发,是种体感上的并发。
异步性:
各个进程间的速度各不相同,呈现出走走停停的特点,推进的速度不可预知。
独立性:
进程是系统分配资源和运行调度的基本单位。

进程与程序的区别:
程序是静态的,是一组指令放在存储中,长期存在。
进程式动态的,是程序的一次执行过程,短期存在。
一个程序可能有多个进程。

2.3.2.进程的结构

进程是一个动态的概念,描述的是运行中的程序,程序由代码和数据构成,并且由于CPU需要在运行的程序之间不断切换,因此每个运行中的程序需要一个地方用来记录自己的一些信息,比如当前执行到了何处,方便CPU切回来时继续执行,还可以记录一些,诸如优先级、名称等重要消息。
这个东西就是PCB(进程控制块)
进程控制块(Process Control Block,PCB):描述进程状态、资源以及和其他进程之间关系的一个数据结构。PCB在创建进程时被创建,进程撤销时同时被撤销。PCB是操作系统管理进程的单位。
因此进程的构成粗粒度上来说为:
程序+PCB
更加细粒度上来说为:
代码+数据+PCB
在这里插入图片描述

2.3.3.进程的状态

理论上进程有三种状态:

  • 运行态(Running):进程占有CPU,在CPU上运行。
  • 就绪态(Ready):具备运行条件,暂未运行,等待CPU资源。
  • 阻塞状态(Block):已经开始执行的进程,在执行过程中等待某个资源。也叫等待状态(wait)。
    以上只是理论上的三种必须的基本状态,各类型操作系统的具体实现会有差异。
    进程间的状态迁移:
    在这里插入图片描述

2.3.4.进程与内存

每个程序的数据和代码装入内存空间,每个进程都会有独立的一个对应的数据结构(内存管理中的页表)来记录该进程的数据和代码存放在哪些位置。
每个程序装入内存,生成对应的一个进程,进程生成时,会同时生成属于该进程的PCB,PCB中会记录页表项,即当前程序执行到了何处。
CPU会根据PCB队列来调度执行各个进程。

2.3.5.多进程图像

由于操作系统为了提高CPU的使用率,支持运行多个程序,启动多个进程,在多个进程之间来回切换,因此多进程图像是操作系统的核心。操作系统感知进程依赖于PCB。
一个正在执行中的进程:
操作系统(2)进程管理(上)进程与线程_第1张图片
等待被调度执行的进程:
在这里插入图片描述
对应的还有阻塞队列等,都是类似上图的结构。
CPU会根据调度算法从就绪队列中选择进程来执行,当执行的进程无法继续推进时,将该进程暂时放入阻塞队列,重新从就绪队列中选一个进程来执行,之前进程重新准备好后,某个时间点上CPU再切回来继续推进该进程。

2.3.线程

2.3.1.概述

线程的出现带来两个优势:

  • 程序之间的切换更加轻量级
  • 并发度更高
    因此可以从以上两个方面来理解线程。
    轻量级:
    为了解决地址冲突问题,在内存中为每个进程单独分配了资源空间,通过一张映射表来完成地址映射。每次切换运行中的程序的时候,这张映射表也要随之切换,总的来说是比较耗时、性能开销比较大的。
    因此提出了优化的方法每次只切换执行的代码。不切换映射表,即不切换资源空间,这样会更加轻量级,于是引出了线程的概念。
    并发度:
    操作系统通过一系列的演化,演化到 如今的“分时系统”阶段,通过将CPU资源切成时间片,加上“中断技术”的加持,已经实现多任务交叉执行,且由于时间片分的足够小,单CPU在使用感上也会有一种程序被并发执行的感觉。到这一步,计算机的资源已经得到较为充分的利用。
    操作系统(2)进程管理(上)进程与线程_第2张图片
    但随着计算机的演进,多CPU系统的出现,随之而来就出现了如下问题:
    例如某个进程得到时间片,在该时间片内,执行的内容如下:
    在这里插入图片描述

由于进程具有原子性,这组操作在在执行过程中不可分割,第一行代码调用IO设备后,即使已经完成使用,后续不再需要此资源,但是在第N行代码执行结束前,IO设备仍然被该进程所占有。单CPU系统下并不会有问题,因为单CPU通过“分时”实现的“伪并发”在当前时间片执行完成前,其他进程也不会被执行。但是在多CPU系统中,程序则是真正以“并发”的方式被执行的,这种由于资源被单个进程所持有,其他需要此资源的进程只能等待。
操作系统(2)进程管理(上)进程与线程_第3张图片
在更细的粒度上优化计算机的资源利用、提高并发性?解决这个问题的思路是——将资源的拥有、调度分开。
于是出现了线程,资源的分配以进程为单位,CPU的调度以线程为单位。原来以进程调度时,是进程各自去争抢资源,没有争抢到的就等待,需要等待争抢到资源的进程整个执行完,时间会很长。引入线程以后,需要相同资源的可以全部到同一进程下去生成线程,线程由于更加轻量,因此支持线程级别的CPU会将时间片分的比进程级别的更小,等待时间会更短。
线程是为了提高并发性而出现的,又称为轻量级进程,是处理机执行的基本单元,是进程中的一个实体,同一进程的线程共享该进程的资源。
到底是以进程进行调度还是以线程进行调度取决于CPU,只支持进程级别调度的CPU就是以进程为单位进行调度,支持线程级别调度的CPU就是以线程为单位进行调度。一旦使用线程级别调度的CPU,进程就只是在逻辑上被执行,进程不会被分配到时间片,承担程序执行功能的是各个线程,被分到时间片的也是各个线程。每个进程至少有一个主线程,其余线程在主线程中创造。

2.3.2.线程的实现

线程的实现有两种:

  • 用户级线程
  • 内核级线程
    用户级线程:
    用户在程序层面通过手动编码的方式来实现逻辑上的线程,通过编码来手动实现线程的切换逻辑,即在用户空间的调度以线程为单位,在CPU上的调度以进程为单位。
    优点:
    CPU一直处于用户态,不需要发生状态跃迁。
    缺点:
    一旦发生用户在编码层面规定的切换条件之外的情况,导致在内核执行中被阻塞了(比如某个线程访问IO设备卡住,导致时间片耗尽),CPU由于无法感知其余逻辑线程的存在,会直接切换为其他进程。

内核级线程:
在这里插入图片描述
用户空间的调度以进程为单位,CPU的调度以线程为单位。
在这里插入图片描述

你可能感兴趣的:(操作系统,后端)