说在前面

今天给大家带来操作系统中进程状态的详解。

本篇博主将通过从进程状态的广泛概念,深入到Linux操作系统详细的一些进程状态。在解释进程状态的过程中,博主还会穿插一些操作系统一些重要概念!本篇干货满满,请大家不要吝啬一键三连哦!

前言

那么这里博主先安利一下一些干货满满的专栏啦!

手撕数据结构https://blog.csdn.net/yu_cblog/category_11490888.html?spm=1001.2014.3001.5482这里包含了博主很多的数据结构学习上的总结,每一篇都是超级用心编写的,有兴趣的伙伴们都支持一下吧!
算法专栏https://blog.csdn.net/yu_cblog/category_11464817.html这里是STL源码剖析专栏,这个专栏将会持续更新STL各种容器的模拟实现。

STL源码剖析https://blog.csdn.net/yu_cblog/category_11983210.html?spm=1001.2014.3001.5482


什么是进程的pcb结构体

首先,我们先要复习一下操作系统概念中的一句很重要的话:先描述,再组织

这其实就是pcb结构体存在的意义

进程的描述

在OS中,对于每一个进程,操作系统都会维护一个pcb结构体来管理每一个进程,每个pcb结构体里面存了有关该进程的信息。

而在Linux操作系统中,pcb结构体成为task_struct结构体

task_ struct内容分类:

标示符: 描述本进程的唯一标示符,用来区别其他进程。

状态: 任务状态,退出代码,退出信号等。

优先级: 相对于其他进程的优先级。

程序计数器: 程序中即将被执行的下一条指令的地址。

内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针

上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。

I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。

记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。

其他信息

进程的组织

可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct链表的形式存在内核里。 查看进程。

广泛意义上的进程状态

广泛意义上的进程状态,其实就是我们在高校计算机科学与技术专业中所修的《操作系统原理》课程中对进程的解释。

这里大家要注意:这种解释是非常广泛的,也就是它可以针对于任何一种操作系统进行解释,都是正确的。但是我们在学习过程中,我们需要深入学习一种操作系统的进程状态,而不是广泛的学习,因此,下一节博主会详细介绍Linux操作系统的进程状态。

此时,我们随便在网上找一张图,其实大同小异,如图所示是博主在写博客时随便找的一张图。

在这里,博主会抓住几个重要的状态进行详细讲解,其余的状态,博主只需要稍微提一下,大家就能够明白了。

新建、运行、阻塞、挂起、死亡

新建

这个状态就是字面意思,进程刚被创建的时候的状态。

概念补充:

这里博主要给大家补充一个概念。在我们的操作系统中,cpu会维护一个叫做运行队列的数据结构。

该数据结构上链接的就是我们进程的pcb结构体。cpu会根据一定的调度算法(调度器决定),对运行队列中的pcb进行运算,即对里面的进程进行运算。(注意:cpu会根据调度算法决定进程的运行顺序,而不是像普通队列一样先进先出)

其中,新建状态指的是,进程的pcb刚被创建,但是还没有进入运行队列时候的状态。(其实在现实操作系统中,并不会存在这种状态,因为pcb结构体一被创建,一般就会直接进入cpu的运行队列中了)

运行

一个进程处于运行态:该进程的pcb在cpu的运行队列中排队或被cpu计算时的状态。

这里要纠正一个常见的误区,运行态不仅仅代表该进程的代码正在被运行,在排队也算运行态。

对于在cpu的运行队列中排队,我们给一个专业的描述:等待cpu资源就绪

阻塞

进程正在等待非cpu资源就绪。(非cpu资源:网卡、磁盘、键盘等)

挂起

如图所示

当内存不足的时候,OS通过适当的置换进程代码和数据到磁盘上时,该进程的状态 

其他的状态博主在详细介绍Linux操作系统的进程状态时给大家解释。

Linux操作系统的进程状态

在介绍状态之前,博主先给大家准备好要用的代码文件

先把Makefile和myproc.c准备好

在大家对Linux的命令行和vim的相关操作十分熟悉后,博主认为大家可以用vscode连接云服务器了,在此之前,博主还是建议大家多操作命令行。

后面我们的代码就在myproc.c中操作,然后make即可。

博主再提供一条打印系统上正在运行进程的脚本命令:

while :; do ps axj | head -1 && ps axj | grep myproc | grep -v grep; sleep 1; done

其中ps axj打印进程,head -1 打印表头,ps axj | grep myproc 打印一个叫myproc的进程,grep - v grep表示不打印grep这个进程(因为我们调用grep搜索,grep这个进程也在跑,Linux中每一条命令都是一个可执行程序,这个大家应该都很熟悉了)while括起来一秒打印一次。

R状态

代码如下:

#include<stdio.h>
#include<unistd.h> int main()
{
while(1)
{
//printf("I am a process!\n");
}
return 0;
}

我们make一下,用脚本打印一下进程,如图所示

 R状态就是运行态,而后面的‘+’代表该进程是一个前台进程。

前台进程

该进程在前台运行,即当我们开启一个命令行(bash)运行该进程,该进程在运行结束之前会占有当前bash,命令行的表现就是:卡住了。

前台进程我们可以通过ctrl C终止,如上图所示。

展示一个R状态的后台进程

那么我们要如何终止该进程呢?

其中一种方式是通过kill命令,并带上9号信号去终止。(现在我们只需要知道kill -9怎么用即可,细节我们不展开)

 讲到这里,我们运行态就讲完了。

从现在开始,博主将不对进程状态后面的+做解释,+就是前台进程的意思,仅此而已。

S状态

对应于我们广泛意义上的阻塞状态(睡眠态)

意味着进程正在事件完成(等待某种非cpu资源)

代码如下 :

#include<stdio.h>
#include<unistd.h> int main()
{
while(1)
{
printf("I am a process!\n");
}
return 0;
}

此时我们肯定会抛出一个疑问:这个代码和R状态的验证代码是一样的,为什么这个会是S?

大家先别急,我们先验证一下 。

此时我们发现,状态中,即有R也有S,这是为什么。

我们大家都知道,我们打印一句话,其实对于操作系统来说,就是一次IO操作。

IO操作的速度是非常慢了,其速度远不及cpu的运算速度。因此一开始我们打印语句,显示器可以跟上cpu的脚步,我们打印的就是R。后面逐渐显示器跟不上了,此时,进程正在等待显示器资源的就绪!因此就是S状态!

此时的S状态是可中断睡眠

可中断睡眠,即我们可以给这个进程发信号!

如果我们ctrl C,会把这个进程杀掉。

如果我们发送kill -9 信号,会把这个进程杀掉。

如果我们发送kill -19 信号,会把这个进程暂停。

在这里我们先不讨论暂停是什么,我们只需要知道,此时的S状态,是可中断睡眠!

D状态

睡眠状态(磁盘睡眠)不可被中断,不可被唤醒!

一个小例子,给大家解释清楚

今天在我们自己的服务器上,我们是无法演示D状态的,因此,通过上面一个小例子的解释,希望大家能明白什么是D状态即可

dd命令可以演示D状态,有兴趣的伙伴可以查一下如何去操作。

T状态

暂停或调试状态

可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可 以通过发送 SIGCONT 信号让进程继续运行。

X状态

我们知道,当一个进程执行完之后,它的资源(task_struct结构体等)资源是需要回收的。

如果操作系统中存在大量的进程个需要同时终止,如果OS不能马上回收所有资源。

此时正在等待资源回收的进程就是X状态,注意:此时这个进程已经死了,它只是在等待回收而已

这是一个瞬时性的状态,我们很难在命令行中看到。

Z状态 僵尸状态

僵尸进程(Zombies)是一个大话题,我们想要完全理解他,需要从是什么?为什么?怎么办?三个角度进行理解。

今天博主将会带着大家理解前两个问号,第三个问号博主会专门再写一篇博客进行讲解!

僵尸状态:当一个进程,死掉的时候,不能被OS立刻清理,还在被检测,被调查死因的时候的状态,叫做僵尸状态!

僵死状态(Zombies)是一个比较特殊的状态。

当进程退出并且父进程(使用wait()系统调用,后面讲) 没有读取到子进程退出的返回代码时就会产生僵死(尸)进程

僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。

所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态

模拟僵尸状态的一个代码

#include <stdio.h>
#include <stdlib.h>
int main() {
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id > 0)
{
//parent
printf("parent[%d] is sleeping...\n", getpid());
sleep(30);
}
else
{
printf("child[%d] is begin Z...\n", getpid());
sleep(5);
exit(EXIT_SUCCESS);
}
return 0;
}

运行结果:

僵尸进程危害

进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!

维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护!

那一个父进程创建了很多子进程,就是不回收,就会造成内存资源的浪费!因为数据结构对象本身就要占用内存,如C语言的结构体,是需要开辟空间的!

如果是C++,析构函数一直都没有被调用!

因此会造成内存泄漏!

如何避免?我们以后再讲,这里不展开了了。

讲到这里,我们所有值得关注的进程状态就已经全部讲完了!下面我们来看看另一种进程

孤儿进程

孤儿进程

僵尸进程是子进程先退出。

那如果父进程先退出,子进程就称之为“孤儿进程” !

孤儿进程不能没有父进程!没有父进程谁来回收他的资源呢?因此它会被被1号init进程领养,由1号进程(init 即系统本身)回收!

代码如下:

让父进程先结束

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
pid_t id = fork();
if(id < 0)
{
perror("fork");
return 1;
}
else if(id == 0)
{
//child
printf("I am child, pid : %d\n", getpid());
sleep(10);
}
else
{
//parent
printf("I am parent, pid: %d\n", getpid());
sleep(3);
exit(0);
}
return 0;
}

运行结果:

这样,我们就验证了我们的结论。

总结

讲到这里,关于进程状态,我们已经有了一定了解了。但是关于Linux OS的进程,还有很多知识点,比如地址空间,优先级等等。博主是很早之前学习了这部分的内容,写博客也是博主的一种复习,因此操作系统的其他内容,博主都会总结并分享学习心得的。希望大家点点赞点点关注,你们的支持是我最大的动力!

( 转载时请注明作者和出处。未经许可,请勿用于商业用途 )
更多文章请访问我的主页

@背包https://blog.csdn.net/Yu_Cblog?type=blog

进程状态|操作系统|什么是pcb|什么是僵尸进程 |什么是孤儿进程 【超详细的图文解释】【Linux OS】的更多相关文章

  1. 1.1 Linux中的进程 --fork、孤儿进程、僵尸进程、文件共享分析

    操作系统经典的三态如下: 1.就绪态 2.等待(阻塞) 3.运行态 其转换状态如下图所示: 操作系统内核中会维护多个队列,将不同状态的进程加入到不同的队列中,其中撤销是进程运行结束后,由内核收回. 以 ...

  2. 【UNIX环境编程、操作系统】孤儿进程和僵尸进程

    基本概念: 在类UNIX系统中,僵尸进程是指完成执行(通过exit系统调用,或运行时发生致命错误或收到终止信号所致)但在操作系统的进程表中仍然有一个进程表表项(进程控制块PCB),处于"终止 ...

  3. [并发编程 - socketserver模块实现并发、[进程查看父子进程pid、僵尸进程、孤儿进程、守护进程、互斥锁、队列、生产者消费者模型]

    [并发编程 - socketserver模块实现并发.[进程查看父子进程pid.僵尸进程.孤儿进程.守护进程.互斥锁.队列.生产者消费者模型] socketserver模块实现并发 基于tcp的套接字 ...

  4. python学习笔记—— 多进程中的 孤儿进程和僵尸进程

    1 基本概述 1.1 孤儿进程和僵尸进程 父进程创建子进程后,较为理想状态是子进程结束,父进程回收子进程并释放子进程占有的资源:而实际上,父子进程是异步过程,两者谁先结束是无顺的,一般可以通过父进程调 ...

  5. day34——僵尸进程和孤儿进程、互斥锁、进程之间的通信

    day34 僵尸进程和孤儿进程 基于unix环境(linux,macOS) 主进程需要等待子进程结束之后,主进程才结束 主进程时刻监测子进程的运行状态,当子进程结束之后,一段时间之内,将子进程进行回收 ...

  6. Perl进程:僵尸进程和孤儿进程

    概念 僵尸进程:当子进程退出时,父进程还没有(使用wait或waitpid)接收其退出状态时,子进程就成了僵尸进程 孤儿进程:当子进程还在运行时,父进程先退出了,子进程就会成为孤儿进程被pid=1的i ...

  7. 多进程wait、僵尸进程、孤儿进程、prctl

    1.概念 1.孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,从而保证每个进程都会有一个父进程.而Init进程会自 ...

  8. 【Linux】僵尸进程,孤儿进程以及wait函数,waitpid函数(有样例,分析很详细)

    本文内容: 1.僵尸进程,孤儿进程的定义,区别,产生原因,处理方法 2.wait函数,waitpid函数的分析,以及比较 背景:由于子进程的结束和父进程的运行是一个异步的过程,即父进程永远无法预测子进 ...

  9. PHP 中的僵尸进程、孤儿进程详解

    僵尸进程 当子进程运行结束,父进程仍然继续运行,但父进程没有对子进程进行回收,释放子进程占用的资源,此时子进程就成为了一个僵尸进程. 在Unix进程管理中,如果新开的子进程运行结束,父进程将会收到一个 ...

  10. [转帖]进程状态的转换与PCB详解

    进程状态的转换与PCB详解 https://blog.csdn.net/qq_34666857/article/details/102852747 挺好的 之前没好好学习.   返回主目录 ​ 之前的 ...

随机推荐

  1. 领域驱动设计(DDD)实践之路(三):如何设计聚合

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/oAD25H0UKH4zujxFDRXu9Q作者:wenbo zhang [领域驱动设计实践之路 ...

  2. element-ui el-menu 刷新保持高亮的写法

    1 <template> 2 <el-menu 3 :collapse="isCollapse" 4 :default-active="defaultA ...

  3. joi

  4. freeswitch两个DTMF转换接口的区别

    概述 freeswitch支持三种模式的DTMF传输方式,分别时inband.INFO.2833. 在传统的PSTN网络中,所有的DTMF码都是inband模式,所以VOIP网络和PSTN网络对接中, ...

  5. Android Kotlin 导入 Protobuf

    project build.gradle plugins { id "com.google.protobuf" version "0.9.1" apply fa ...

  6. 杂谈 | 在 SEU 开会可以去哪里

    空间预约: 健雄书院预约系统 只对吴院人开放,其他人可通过前台志愿者预约. 秉文书院对全校开放(貌似?),需要 提前一天 预约. 借教室需要 提前两天 申请. 图书馆研讨间可以随时约,只是有点难抢. ...

  7. Nginx IP地址较少时如何合理分配后端服务资源

    Nginx IP地址较少时如何合理分配后端服务资源 背景 客户系统很多时候会通过网闸或者是VPN登录到产品内 此时的IP地址一般是相同的. 这种情况下较难实现根据ip地址使用ip_hash的方式将压力 ...

  8. [转帖]AF_UNIX和AF_INET

    https://www.cnblogs.com/shangerzhong/p/9153737.html family参数代表地址家族,比较常用的为AF_INET或AF_UNIX.AF_UNIX用于同一 ...

  9. [转帖]在麒麟linux上安装Postgresql12.5

    https://jimolonely.github.io/tech/linux/install-postgresql-kylin/ 本文主要实践在麒麟V10版本上通过源码编译安装PostgreSQL1 ...

  10. 【转帖】MySQL InnoDB存储原理深入剖析与技术分析

    一.MySQL记录存储: MySQL InnoDB的数据由B+树来组织,数据记录存储在B+树数据页(page)中,每个数据页16kb,数据页 包括页头.虚记录.记录堆.自由空间链表.未分配空间.slo ...