鹅厂进击OS系列(二):进程三连

鹅厂进击OS系列(二):进程三连

今天风和日丽,家里蹲的我十点钟听了三分钟的鸣笛,心里好感慨,希望山河世代无恙。
下午追完了剧,暂时剧荒了,跟gg说在家学习,对待接下来的面试,他说不如替他写毕设哈哈哈,今天也是想吃海底捞的一天。
下午睡醒了,终于把早上这篇托更的博客完善好了,可能理解有不对的地方,望指正。

一、初识进程

1.进程是什么

​ 进程的经典定义是一个执行中程序的实例。系统中的每个程序都运行在某个进程的上下文中,学习OS的时话,经常看到课本上提起上下文这个概念,其实上下文就是由程序正确运行所需的状态组成的。这个状态包括存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量还有打开文件描述符的集合。

​ 进程就可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如记事本、画图、浏览器 等),也有的程序只能启动一个实例进程(例如网易云音乐、360 安全卫士等)

​ 进程是系统进行资源分配和调度的一个独立单位,进程包括程序段、数据和PCB

​ 提起进程,自然想到线程,下面从几个方面对比一下,帮助更好的理解进程和线程的概念。

进程
程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,数据加载至内存。在 指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO的当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。
线程
一个进程之内可以分为一到多个线程。 一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给 CPU 执行 Java 中,线程作为小调度单位,进程作为资源分配的小单位。 在 windows 中进程是不活动的,只是作为线程的容器。

​ 二者的关系就好比火车和车厢的关系一样,线程是进程的一个实体。
在这里插入图片描述
​ 为什么这么说呢?一节车厢只属于一个火车,一个火车却有好几节车厢,火车前进可以看作是车厢在不停运动。以此类推:

  • 一个线程只属于一个线程。
  • 一个进程可以有多个线程。
  • 在处理机上进行的是线程。
  • 不同进程的线程利用消息通信的方式实现同步。

​ 但是,你仔细一瞧,线程和进程又有很大的不一样。从四个方面我们来说说。

  • 调度:线程是系统调度和分配的单位,进程是作为拥有系统资源的基本单元。

  • 开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。

  • 并发性:同一进程或不同进程内的线程都可以并发执行。如果是用户级线程, 线程是由进程进行管理的, 那么对于OS而言就不存在线程这个概念, 那么就是进程可以并发执行, 一个进程内的线程串行执行; 而内核级线程则一个进程内的线程也可以并发执行。

  • 内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。进程有自己的独立地址空间,所以崩了也没啥事情,但是线程有自己的独立堆栈却没有独立的地址空间,一个线程崩溃,全部GG。

我认为深刻的理解内存分配方面的区别,对于在回答一些多线程单线程的问题是,很有帮助,因为你知道线程是没有独立的地址空间的,一毁皆毁。

2.进程控制块PCB

​ 为了让程序(含数据)能独立运行,应该配置进程控制块,它记录了操作系统所需要的、用于描述进程的当前情况以及控制进程运行的全部信息。这个PCB非常重要,那么它的重要性是怎么体现的呢?

​ 当操作系统要调度某个进程执行的时候,要从这个进程的PCB中查出其现行状态及优先级;在调度后,还要根据其PCB中保存的处理及状态信息,设置该进程恢复运行的现场,并根据其PCB中的程序和数据的内存始址,找到对应的程序和数据;进程在执行的过程中,如果要和其它进程实现同步通信,也需要访问PCB;如果进程要暂停执行,那也需要其断点的处理机环境保存在PCB中。

​ 显然,PCB应该是一个经常被系统访问的东西,所以应该把它放在内存里,系统将所有的PCB组织成若干个链表(后面有说),存放在OS中专门开辟的PCB区。

​ PCB的主要内容围绕四大部分,分别是标识信息、说明信息、现场信息和管理信息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iO60ANuP-1586013085439)(C:\Users\NayelyA\AppData\Roaming\Typora\typora-user-images\image-20200404112409940.png)]

​ 与此相关的,还有三种不同的进程控制块队列,运行队列、就绪队列、阻塞队列。
在这里插入图片描述

3.进程的基本状态

​ 很多书中介绍进程基本状态时,一般都是三种状态。

1) 就绪(Ready)状态

​ 当进程已分配到除 CPU 以外的所有必要资源后,只要再获得 CPU,便可立即执行,进程这时的状态称为就绪状态。在一个系统中处于就绪状态的进程可能有多个,通常将它们排成一个队列,称为就绪队列。

2) 执行状态

​ 进程已获得 CPU,其程序正在执行。在单处理机系统中,只有一个进程处于执行状态;在多处理机系统中,则有多个进程处于执行状态。

3) 阻塞状态

​ 正在执行的进程由于发生某事件而暂时无法继续执行时,便放弃处理机而处于暂停状态,亦即进程的执行受到阻塞,把这种暂停状态称为阻塞状态,有时也称为等待状态或封锁状态。

​ 致使进程阻塞的典型事件有:请求 I/O,申请缓冲空间等。通常将这种处于阻塞状态的进程也排成一个队列。有的系统则根据阻塞原因的不同而把处于阻塞状态的进程排成多个队列。

​ 处于就绪状态的进程,在调度程序为之分配了处理机之后,该进程便可执行,相应地,它就由就绪状态转变为执行状态。正在执行的进程也称为当前进程,如果因分配给它的时间片已完而被暂停执行时,该进程便由执行状态又回复到就绪状态;如果因发生某事件而使进程的执行受阻(例如,进程请求访问某临界资源,而该资源正被其它进程访问时),使之无法继续执行,该进程将由执行状态转变为阻塞状态。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-frlXfZ7S-1586013085440)(C:\Users\NayelyA\AppData\Roaming\Typora\typora-user-images\image-20200404111331045.png)]

​ 也有进程5种状态的说法,这是在3种状态基础上加入了创建状态和终止状态。

1)创建状态

​ 创建一个进程一般要通过两个步骤:首先,为一个新进程创建 PCB,并填写必要的管理信息;其次,把该进程转入就绪状态并插入就绪队列之中。当一个新进程被创建时,系统已为其分配了 PCB,填写了进程标识等信息,但由于该进程所必需的资源或其它信息,如主存资源尚未分配等,一般而言,此时的进程已拥有了自己的 PCB,但进程自身还未进入主存,即创建工作尚未完成,进程还不能被调度运行,其所处的状态就是创建状态。

​ 引入创建状态,是为了保证进程的调度必须在创建工作完成后进行,以确保对进程控制块操作的完整性。同时,创建状态的引入,也增加了管理的灵活性,操作系统可以根据系统性能或主存容量的限制,推迟创建状态进程的提交。对于处于创建状态的进程,获得了其所必需的资源,以及对其PCB初始化工作完成后,进程状态便可由创建状态转入就绪状态。

2)终止状态

​ 进程的终止也要通过两个步骤:首先等待操作系统进行善后处理,然后将其 PCB 清零,并将 PCB 空间返还系统。当一个进程到达了自然结束点,或是出现了无法克服的错误,或是被操作系统所终结,或是被其他有终止权的进程所终结,它将进入终止状态。进入终止态的进程以后不能再执行,但在操作系统中依然保留一个记录,其中保存状态码和一些计时统计数据,供其它进程收集。一旦其它进程完成了对终止状态进程的信息提取之后,操作系统将删除该进程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PuNtgXDE-1586013085443)(C:\Users\NayelyA\AppData\Roaming\Typora\typora-user-images\image-20200404112125420.png)]

​ 当然还有挂起状态,加上挂起这个图会更加复杂,这里就不详细介绍了。

4.用户模式和内核模式

面试官:同学你好,下面来问问操作系统的相关知识,请你谈谈自己对用户态和内核态的理解。

我:这要从进程开始说起…

​ 通过实现两种不同的模式可以限制一个应用可以执行的指令以及它可以访问的地址空间范围

​ 处理器通常是用某个控制寄存器中的一个模式位来提高此功能,这个寄存器就记录了进程当前拥有什么样的特权。如果设置了模式位,进程就处于内核模式运行在内核态的进程可以执行指令集中的任何指令,并且可以访问系统中的任何内存位置

​ 那么,没设置模式位的时候,进程显然就在用户模式里了。用户模式中的进程不允许执行特权指令,啥叫特权指令?

img

​ 比如说停止处理器、改变模式位以及发起I/O操作这都算是特权指令。处于用户态的进程,是能直接引用地址空间中内核区内的代码和数据,我们可以理解为越权了,那如果必须要用可咋办呢?不慌,通过系统调用接口间接访问内核代码与数据就可以了。

​ 到这里,基本的一些概念我已经叨叨完了,或许你和我一样好奇,内核态和用户态什么时候会切换呢?在这里,可以稍微透露透露,从用户态切换到内核态的唯一方法就是通过中断、故障或者现如系统调用这样的异常实现。在简单提一下,Linux中提供了/proc文件系统,这种机制可允许用户模式进程访问内核数据结构的内容。具体的用户态向内核态转变的过程,先埋个坑,后面的文章说。

5.上下文切换

​ 在学习Java高并发的时候,经常看到这个词,一直不大理解,今天揪出来好好说说。

​ 操作系统内核使用一种叫做上下文切换的较高层次形式的异常控制流来实现多任务。内核为每一个进程维持一个上下文,上下文其实是内核重新启动一个被抢占的进程所需的状态,通用目的寄存器、浮点寄存器、程序计数器、用户栈、内核栈等等数据结构的值共同构成上下文。

​ CSAPP这本书中提到:

在进程执行的某些时刻,内核可以决定抢占当前线程,病虫开始一个先前被抢占了的进程,这种决策就要做调度,是由内核中成为调度器的代码处理的。

当内核选择一个新的进程运行时,我们说内核调度了这个进程,当然了具体要怎么调度,是有对应的调度算法的(比如时间片轮转、先来先服务等等)。在内核调度了一个新的进程运行后,就要抢占当前进程,并且使用一种称为上下文切换的机制来将控制转移到新的进程(这句话可能有些拗口)。

​ 上下文切换主要做三件事,首先保存当前进程的上下文,然后恢复某个先前被抢占的进程被保存的上下文,最后把控制传递给这个新恢复的进程。

img

​ 啥时候上下文切换呢?中断、当内核代表用户执行系统调用时就可能会发生。比如,sleep系统调用,它会显示地请求让调用进程休眠。

二、进程的创建与终止

1.进程的创建

​ 一个进程是怎么创建的,这要从引起创建进程的事件说起…在操作系统中,下列事情将会引发进程创建。

  • 1)用户登录:在分时系统中,用户在终端键入登录命令。
  • 2)作业调度:批处理系统中,载入一项作业。
  • 3)提供服务:由操作系统核心(系统程序模块)创建服务进程。如打印请求 。
  • 4)应用请求:存在的进程创建新的进程。由应用进程(父进程)创建。

​ 那么一个进程是如何诞生的呢?通过前文想必我们已经清楚进程的组成了,没错,进程的诞生和它的组成有关系,尤其是PCB!在介绍创建态的时候,其实已经简单介绍过。

1) 申请空白的PCB:分配进程标识符,从PCB集合中申请一个空闲的PCB。
2)为新进程分配内存等资源。
3)初始化进程控制块PCB。

  • 初始化标识符信息。将进程标识符、父进程标识符填入新PCB中。

  • 初始化处理机状态信息。使程序计数器指向程序的入口地址,栈指针指向栈顶。

  • 初始化处理机控制信息。将进程置为就绪状态。

4)将新进程插入就绪队列。

2.进程的终止

​ 进程终归要终止,一个进程不是正常结束就是异常结束,或者是在外界干预的情况下结束。

​ 在批处理系统中,如果程序执行中遇到了Holt指令,那么就要产生一个中断,通知操作系统本进程完事了,这属于正常结束,在分时系统中表示进程完毕的是Logs off,也是产生中断然后通知操作系统。

​ 异常结束呢,情况就比较多了,比如非法指令、运行超时、等待超时、I/O故障等等;至于外界干预,比如死锁,父进程请求终止子孙进程,父进程终止等等情况。

​ 上面说的情况一旦发生,就要调用终止原语然后按照下述流程终止:

  • 根据被终止进程的标识符,从PCB集合里找到它,读取进程状态。
  • 若处于执行状态,立即终止,设置调度标志为真(表示该进程被终止后应重新进行调度)。
  • 要是这个进程还有子子孙孙,那也应该扼杀它的子孙们。
  • 没收终止进程的所有资源,如果是子孙进程,那就还给父进程,如果是父进程,那就还给系统。
  • 把终止进程的PCB从所在队列里移出去。

三、进程阻塞与唤醒

1.如何引起进程阻塞/唤起
事件说明例子
请求系统服务进程请求OS提供服务,但是OS没法立刻满足。系统已将打印机分配给其他进程而不能分配给请求进程,此时进程被阻塞。
启动某种操作当进程启动某种操作后,如果该进程必须在该操作完成之后才能继续执行,则必须先使该进程阻塞,以等待该操作完成。通过WPS启动了打印机(I/O设备),但是此时打印机正在打印其它文档(执行别的I/O操作),那么就需要等打印完了,WPS进程继续执行。
新数据尚未到达对于相互合作的进程,如果其中一个进程需要先获得另一(合作)进程提供的数据后才能对数据进行处理,则只要其所需数据尚未到达,该进程只有(等待)阻塞。有两个进程,进程 A 用于输入数据,进程 B 对输入数据进行加工。假如 A 尚未将数据输入完毕,则进程B将因没有所需的处理数据而阻塞;一旦进程 A 把数据输入完毕,便可去唤醒进程 B。
没有新工作系统往往设置一些具有某特定功能的系统进程,每当这种进程完成任务后,便把自己阻塞起来以等待新任务到来。系统中发送进程主要任务就是发数据的,如果数据全发完了也没有新的活让它做,此时就会阻塞。

2.进程阻塞过程

​ 进程的阻塞是一种主动行为,通过原语block()完成。进程从运行态转变到阻塞态,首先需要立即停止执行,把PCB中的状态修改为阻塞,将PCB放到阻塞队列中。然后通过重新调度,将CPU资源分配给其它就绪的进程并切换上下文。

3.进程唤醒过程

​ 通过唤醒原语wakeup()实现。首先把阻塞的进程从阻塞队列里一出去,然后修改PCB中的进程状态,然后把PCB放到就绪队列里。就绪队列有1个,而阻塞队列可以有好几个(不同事件的阻塞队列)。

四、进程的挂起与激活

建议这里结合进程转换图去理解,由于篇幅限制,本博没有具体讲解包含挂起、激活的进程状态。

1.进程的挂起

​ 用户进程请求可以把自己挂起,父进程请求挂起自己的某个子进程也可以。系统会通过原语suspend()将指定进程或者处于阻塞状态的进程挂起。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LCUGEzOi-1586013085445)(C:\Users\NayelyA\AppData\Roaming\Typora\typora-user-images\image-20200404223112475.png)]

2.进程的激活

​ 如果父进程或者用户进程请求激活指定进程,如果该进程驻留在外存而且内存中有足够的空间,那么可以将在外存上处于静止就绪状态的该进程换入内存。此时用到的原语是active()

     [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LqReijJr-1586013085446)(C:\Users\NayelyA\AppData\Roaming\Typora\typora-user-images\image-20200404224013894.png)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值