OS-进程

Posted temporary2021.6期末复习版

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OS-进程相关的知识,希望对你有一定的参考价值。

操作系统–进程

进程概念
程序的顺序执行:仅当前一操作(程序段)执行完后,才能执行后继操作。
如下图所示:
在这里插入图片描述
我们当然知道需要按序执行S1->S2->S3。因为b需要a,c需要b。
顺序执行的特征:
顺序性:即下一操作需要等待上一操作的完成。
封闭性:程序在运行时会独占资源。
可再现性:重复执行同一程序会产生相同的结果。

根据上述所述,我们引出了“前趋图”的概念。
图中,我们用一个结点表示一个进程。而用有向边“->”表示一种偏序关系,例如Pi->Pj中我们称Pi是Pj的直接前趋,Pj是Pi的直接后继。
在图中没有前趋的结点称为初始结点,没有后继的就是终止结点。
每个结点会有权值weight,表示进程需要的时间或含有的程序量。
前趋图中,“环”是不允许的!如下图所示:
在这里插入图片描述
这就好比:
S1: a = x + 1
S2: b = a + c
S3: c = b + a
显然,不可解!所以印证上述的结论,前趋图中不能出现“环”!

程序除了“串行”执行,还可以“并行”,如下图就是程序的并发执行:
在这里插入图片描述
不难看出I1结束后C1和I2可以同时执行,而再进一步I3,C2和P1是可以并行的!
得到的结论就是Pn,Cn+1,In+1是可以并行的。

并发执行引发的问题,会失去封闭性。
比如某时P1、C2、I3同时执行必然是共享CPU资源的,不会有一个进程独占的情况。
会丧失可再现性,书中的例子如下:
在这里插入图片描述
我们无法预知N = N + 1和Print(N)、N = 0的顺序,所以有如下的情况:
在这里插入图片描述
由上所知,程序的并发执行未必会得到我们期望的结果,于是引入进程的概念。
进程由程序、数据和进程控制块三部分组成
程序:描述进程要完成的功能,代码段
数据:进程执行时所需要的数据区,数据段
进程控制块PCB:一种数据结构,用于标识进程的存在,记录进程执行过程各个时刻的状态特征。

内核PCB数据结构具体解析可以自行百度,有比较好的blog。
进程特性如下所示,比较好理解,到时候临时抱佛脚背一下:
在这里插入图片描述

这句话是ppt上老师标红的重点部分:
进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位

正确认识程序和进程的区别:
程序就是一串指令(我们平时写的代码编译链接成为机器指令)和数据的集合,长久的存在于存储器中。程序可以由多个进程并发地执行完成。
相较而言进程就是动态的运行,占用CPU且最后执行完毕后会消亡,释放CPU。

进程的三种基本状态:
就绪态是进程获得了CPU以外的所有资源,处于就绪队列。
被调度后其实就是获得了CPU资源,就会进入执行态。
执行态可能由于请求I/O资源而进入阻塞状态,会放弃CPU资源。
在这里插入图片描述
在我们引入“挂起”的概念后会得到如下一张状态转换图:
为什么要挂起呢?可能是终端用户要调试程序了,也有可能是父进程等子进程同步,比如父进程fork后调waitpid……
一个完整的状态表我们还会引入“创建”和“终止”态,创建仅拥有了PCB但还没获得资源且未进入调度队列用于初始化。
终止即释放所有资源,且结束后不能再获得CPU!
在这里插入图片描述

PCB的一些比较基本的理解和信息:
在这里插入图片描述

进程标志符,我们在C中调getpid可以得到进程的唯一标志,id号。

PCB的组织方式

1.线性组织方式。
将所有PCB存放到一张专用表中,记录该表的首地址。虽然这是一种简单的实现方式但比较低效,每次都要搜索整张表才行。

2.链接组织方式
把具有相同状态(阻塞、执行、就绪、空闲)的PCB分别链接成一个队列。
示意图如下所示:
在这里插入图片描述

3.索引方式。
通过建立索引表的方式进行实现,索引表的首地址会被存放于内存中。
索引表的表项记录的是相应状态的PCB在PCB表中的地址。
在这里插入图片描述

进程控制

我们会把进程家族描述成一颗有向树,根节点就是子树的祖先。我们在Linux操作系统下可以在终端调用命令“pstree”来观察此种现象。
在这里插入图片描述
在树的概念里直接相连的我们称之为“父子”关系,同样是适用于进程的。父子进程间有如下的一些特性:
在这里插入图片描述
这些文字内容都比较容易,即使是通过C来进行实现和观察也并不困难。

来系统里我们包含了一些“原语操作”,比如我们调用block进行阻塞、调用active进行激活、suspend进行挂起,所谓原语操作定义如下:
在这里插入图片描述
我们讨论了一些会引发创建进程的事件:
用户登录成功后,系统为用户创建一个进程插入就绪队列。
作业调度,就是有进程被调度算法调度后,调入内存,为其分配PCB。
提供服务,用户有需求时系统会分配一个进程针对进行服务。
上面三者都是系统内核创建进程。
应用请求时用户自己创建新进程,比如用户需要从终端输入字符串同时又要对数据进行处理最后要输出,可以分配三个进程并发地执行。
在这里插入图片描述
进程的创建其实也是涉及了系统原语操作的,即“Create”。
整个create的操作步骤如下所示:
在这里插入图片描述
其中分配资源阶段,除了交互型是由系统分配一定大小的空间外,其余两种都需要在创建时就给出所需内存的大小。

初始化控制块阶段:把刚刚(第一步)获得的pid填入。填入执行程序的入口地址栈指针指向栈顶。设置进程状态,就绪或静止就绪,初始化一个最低优先级,当然用户也可以显示地设置为高优先级。

有创建就有终止。
引发终止的一些事件如下所示:
在这里插入图片描述
批处理系统正常结束有一条Halt指令,分时系统中就是Logs off。
后面一些非正常结束的事件也都是比较好理解的。

终止的流程如下所示:
在这里插入图片描述
我觉得要记住的一点就是第二步,如果某进程被检索到,企图对其终止自身却还处于执行状态时应该置调度标志为真。由于其并未结束,后续应该被重新调度。

Linux下我们用很形象的“kill”杀死进程,而在windows下我们可以用tskill。

接下来还有两个操作就是进程的阻塞和唤醒。
我们同样需要先了解一下可能引发上述两操作的事件:
1.向系统请求共享资源失败。如某一进程请求打印机资源,但此时或许打印机已经分配给其他进程,那么当前进程只能陷入阻塞。
2.等待某种操作的完成。如当前进程请求了I/O资源,当I/O设备启动后当前进程就应主动陷入阻塞状态,等待至I/O运行完毕此进程才被唤醒。
3.新数据尚未到达。比如两进程A、B。A用于输入数据,B用于处理数据。若A未将数据传入设备B就只能陷入阻塞。当A数据接收完毕,B被唤醒。
4.等待新任务的到达。比如网络中的发送进程,当有数据包时处于执行状态进行数据包的发送,当发送完毕后就陷入阻塞,等待新的数据包的到来。

阻塞也会调用原语“block”操作。阻塞的流程如下:
在这里插入图片描述
唤醒调用原语操作“wake up”,唤醒的流程如下所示:
在这里插入图片描述

还剩最后两个操作就是挂起和激活。
挂起的流程示意图如下:
在这里插入图片描述
激活的过程:
在这里插入图片描述

以上是关于OS-进程的主要内容,如果未能解决你的问题,请参考以下文章

多任务编程 -- 进程相关函数 os.getpid()os.getppid()os._exit()sys.exit()

多任务编程 -- 进程相关函数 os.getpid()os.getppid()os._exit()sys.exit()

golang 进程创建,fork,以及热重启(无缝升级)

OS进程/线程切换

python调用OS.system结束进程问题?

OS——进程与线程