【Linux】-进程概念及进程状态(僵尸进程和孤儿进程)

在这里插入图片描述
💖作者:小树苗渴望变成参天大树🎈
🎉作者宣言:认真写好每一篇博客💤
🎊作者gitee:gitee✨
💞作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法🎄
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

文章目录

  • 前言
  • 一、初步认识三种状态:
    • 1.1运行态
    • 1.2阻塞态
    • 1.3挂起态
  • 二、Linux上的状态
    • 2.1R状态
    • 2.2S状态
    • 2.3D状态
    • 2.4T和t状态
    • 2.5Z和X状态
  • 三、总结


前言

上篇我们刚刚讲解完毕task_struct里面的第一个内容标识符,也讲解了fork的具体作用和用途,今天这篇我在带大家来学习task_struct里面另一个属性-进程状态,这个也是非常重要的,由于内容比较多,所以我选择单独一篇博客给大家介绍,希望大家可以更好的理解,此篇主要是概念,所以文字相对较多,代码相对较少,也希望各位读者可以耐心的阅读下去,话不多说,我们开始进入正文


task_ struct内容分类

标示符: 描述本进程的唯一标示符,用来区别其他进程。
状态: 任务状态,退出代码,退出信号等。
优先级: 相对于其他进程的优先级。
程序计数器: 程序中即将被执行的下一条指令的地址。
内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
上下文数据: 进程执行时处理器的寄存器中的数据。
I/O状态信息: 包括显示的I/O请求分配给进程的I/O设备和被进程使用的文件列表。
记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
其他信息

一、初步认识三种状态:

我们先从一般的操作系统学科来介绍三种常见的状态:运行,阻塞,挂起
还有其他状态都不是特别的重要,然后我们再来学习Linux上的状态是什么样的,我们在网上找一些操作系统状态图
在这里插入图片描述

相信大家对这些名词几乎不了解,可能也没有听说过,接下来我就给大家进行解释

1.1运行态

在这里插入图片描述

通过这个图相信大家已经理解了什么是运行态了吧

1.2阻塞态

这个状态不太好理解,还是需要画图来能给大家去介绍的
在这里插入图片描述

阻塞态是进程和外设之间的资源请求,通过外设输入数据让进程可以继续运行下去,相信大家应该了解了进程的阻塞态了吧

1.3挂起态

挂起态可以说是在阻塞态的基础上产生的状态
在这里插入图片描述

相信大家此时对挂起态有了一定的了解了

通过上面的三种进程的状态的了解,我们来看看Linux上是怎么处理他上面进程的状态

二、Linux上的状态

在这里插入图片描述
我们有这么多状态,博主都会一一介绍的,大家不用担心。

2.1R状态

Linux的R状态就是运行状态和我上面介绍的运行态是一样的道理,在运行队列里面就是运行态
我们来看一段代码:

#include<stdio.h>
int main()
{
    while(1)
    {
        printf("我是一个进程\n");
    }
    return 0;
}

#include<stdio.h>
int main()
{
    while(1);
    return 0;
}

在这里插入图片描述

第一个程序和第二个程序都是写了一个死循环,而且都是没有在终止进程的时候去查看的,为什么第一个程序是S状态,而第二个程序是R状态首先S状态先理解为阻塞状态,我们的cpu运行太快了,因为第一个程序是一个死循环,所以肯定不止在cpu上就跑一次,他应该一直从cpu被拿下被放上,在运行队列里面待着,但是他每次放下来需要去打印,由于打印是和外设打交道,而外设太慢了,所以不能一直放在运行队列中等待排队,万一又到我这个程序开始运行了,但我还在往外设的显示器是慢慢打印呢,这时候是不是就没有准备好,所以就不能放在运行队列上,此时应该在等待队列上等待打印,等打印好了,又会被放到运行队列,在跑下一次,由于速度都很快,我们观察到的结果就是一直在运行的状态给我们一定的错觉,大部分时间都在等待队列待着等待打印,所以我们大概率看到都是S状态那第二个程序呢?他由于没有与外设打交道,所以他是一直在运行队列,不停的拿上拿下,但始终在运行队列中,所以看到就是R状态

我们看到状态后面的+号是什么?
他标识前台运行,意味我们其他程序跑不了,因为他一直在运行,我们命令都输入不了,我们可以在运行的时候加一个&让他变成后台运行./myproc &
在这里插入图片描述
此时就是后台运行,由于后台运行没有办法使用CTRL+c结束程序,所以我们必须使用这个命令把程序杀死kill -9 PID,-9是一个信号,一会还会介绍到其他两个信号。
在这里插入图片描述
相信大家对Linux上的R状态(运行状态)应该有所了解了吧

2.2S状态

我们在R状态提到过,S状态,我们可以暂时理解为阻塞态,在Linux上我们理解为睡眠状态:意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。可中断请求就是可以随时被唤醒,介绍R状态的时候我们往显示器去打印,就是等待打印任务完成,当正在打印的时候,就是睡眠状态,打印好了就被唤醒了。

我们来看案例:

#include<stdio.h>
int main()
{
     int n=0;
     scanf("%d",&n);                             
     return 0;
}

在这里插入图片描述

我们等待键盘输入的时候就是在等待事件的完成,所以是处于S状态.


我们在来看看我们的bash程序:
在这里插入图片描述

大小S不用管都是属于睡眠状态,我们的bash就是命令行解释器,等待我们输入命令,就是等待事件的完成,所以也是阻塞态,只要是和外设有交流的进程都可以理解为睡眠状态(只包括浅度睡眠),不止是键盘和显示器。

我们大部分看到的进程都是处于阻塞态,为了显示效果,写特殊的代码让大家看到其他状态。相信到这个时候大家对Linux上的S状态(浅度睡眠状态)应该了解了吧。

2.3D状态

这个状态和睡眠状态很像,上面叫浅度睡眠,可以随时被唤醒,而D状态他叫深度睡眠,不可中断的睡眠状态,不会相应任何人的命令,这个状态不太好展示的,有可能造成数据丢失,所以我将会以一个小故事的形式来给大家进行展示:

小故事时间:

D状态也叫睡眠状态,他的操作是等待IO时间完成,这时候我们的进程假设要将1GB的数据放到磁盘里面,磁盘跟进程说,你这个1GB数据不一定能放的下,放不放的下我到时候到来跟你说一声,万一放不下去,我在把已经放下数据在还给你,你先等我一下,我速度很慢的,此时的进程就翘着二郎腿在等啊等啊,此时操作系统路过了,他正在清理占用资源的进程,此时发现这个进程有没有在使用,说你等啥等呢,浪费我内存的资源,直接给这个进程清理掉了,此时硬盘放着放着发现放不下,就不好意思的回来告诉进程,可进程去不见了,硬盘就不知道怎么办了,硬盘心想我不知道还给谁啊,但别的进程还有放数据进来啊,不能占用资源啊,直接给丢掉了,万一这是一个非常重要的银行转账记录,那损失可就大了。


此时就来了一法官,他要追究到底是谁的责任啊
操作系统辩论:法官大人,这可不能怪我啊,我们的本质工作就是维护进程,管理内存空间,他占用内存资源,导致内存严重不足,数据丢失和我没有关系,我只管合理分配内存空间给进程使用,如果不清理他,导致其他进程崩溃,那样损失更大,该丢的数据还是得丢失
磁盘辩论:法官大人,这事和我也没有关系,我放的时候就已经和进程说了可能放不进去,让进程等待我一下,我就是一个打工人,别人说什么就是什么可最后他人却不见了,我也不知道把数据放在哪里,其他进程还要放数据呢?不能耽误别人,我没有办法只有丢掉
进程辩论: 法官大人,我才是受害者啊,我在等待磁盘给我回复的过程中,操作系统直接来二话不说给我带走了,这不是自己的行为,我i也没办法啊


法官大人听了三个人的辩词说的都有道理,也不知道判定是谁的问题了,好心的法官就自己承担了此次损失,好在法官是程序员,进程和磁盘工作好好的,是操作系统路过把两人直接的交流打断的,索性法官直接修改操作系统,给此进程一个免死金牌,任何响应都不能影响此进程和磁盘直接的交流,操作系统也不行,所以此时的进程就处于深度睡眠状态,没有人可以中断他,也叫D状态

现在都是固态硬盘速度也是比较快的了,所以进程不需要怎么等待硬盘的回复,所以也很少出现D状态,偶尔出现一个就不得了,出现多了那么你的操作系统肯定就会挂掉。所以D状态我们知道是什么就行了,我就不给大家验证了,博主怕自己的linux操作系统崩溃掉😂,相信到这里大家对D状态(深度睡眠状态)已经有所理解了吧

2.4T和t状态

这两个目前没有啥区别,我们当成一个状态就行了

T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
我们来看案例:

 #include<stdio.h>  
 int main()  
 {
       while(1)
       {
           printf("我一会就要停止运行啦\n");       
       }  
       return 0;
  }  

在这里插入图片描述
9号信号我们刚才已经使用过了,是杀掉进程的,19号信号是停止程序,18号信号是恢复程序。

停止: kill -19 PID
在这里插入图片描述
恢复: kill -18 PID
在这里插入图片描述
我们看到我们恢复之后就默认变成后台运行,为啥看到是S这里我就不多说了。


我们最常见停止程序是什么??gdb 他不打断点r是直接运行结束,打了断点会在断点处停止,我们需要将我们的程序加-g选项,才能调试
我们来看测试:
在这里插入图片描述

所以我们的断点里面肯定也有一些关于停止信号的命令,导致程序可以被暂停。相信到这里大家对停止状态已经有所了解了吧

2.5Z和X状态

这两个状态是有一个先后关系的,先是X状态然后到X状态,先来介绍一下神叫做Z状态

Z(zombie)-僵尸进程:

  1. 僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程
  2. 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
  3. 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态

大家肯定不理解,此时又到 小故事时间

有一天你悠闲的在路上小跑,突然有一个人飞速的跑过去,然后在你前方两百米的地方突然躺平了,你跑过去处于好心,拨打了119和110,此时119快速的来到了现场,然后发现这俄格人救不活了,然后就撤了,此时110来了,他第一件事情不是直接清理现场,而是要保护现场,找法医来看看死者的死因是什么,然后拉起禁戒线,等待家属来,这段时间这个人会一直在这躺着。此时就好比进程一直处于僵尸状态。


那么到底谁最关心你的死活,是不是就是家属,在Linux中就是父进程,他最关系你了,他需要把你的尸体清理带走,在Linux中,父进程就要清理子进程退出后的代码,如果父进程一个不清理读取的话,那么此时的子进程就一直会在哪没人清理,处于僵尸状态。

所以这个时间大家对僵尸进程是不是有所了解了,就是子进程推出后,父进程一直不读取他的退出码,他就一直清理不掉,处于僵死状态,所以我们需要使用fork来创建父子进程,来测试我们想要的效果:

  1 #include<stdio.h>                                                                  
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 int main()
  6 {
  7     pid_t id=fork();
  8     if(id==0)
  9     {
 10         int cnt=5;
 11         while(cnt)
 12         {
 13             printf("我是子进程,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt--);
 14             sleep(1);
 15         }
 16         exit(0);//主动让进程退出,而不是程序退出了他在退出,模拟父进程在运行没有时间清理父进程
 17     }
 18     else if(id>0)
 19     {
 20 
 21         while(1)
 22         {
 23             printf("我是父进程:pid:%d,ppid:%d\n",getpid(),getppid());
 24             sleep(1);
 25 
 26         }
 27     }
 28     return 0;
 29 }

使用此命令监视进程状态:while :; do ps axj | head -1 && ps axj | grep myproc | grep -v grep ; sleep 1 ; done

在这里插入图片描述
我们发现子进程退出之后父进程在忙着运行自己的程序还没有读取到子进程的退出码,所以子进程一直是处于僵尸状态,这个单词defunct这就是死的意思。

显然僵尸进程是不好的,所以来说说僵尸进程有哪些危害:

  1. 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!
  2. 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护?是的!
  3. 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!
  4. 内存泄漏?是的!
  5. 如何避免,后面介绍

说完Z进程,我们来看看X进程:这个状态只是一个返回状态,你不会在任务列表里看到这个状态,他是一个瞬时的状态。


接下来我们再来介绍一下另一个进程-孤儿进程
上面的僵尸进程是子进程先退出,父进程没有及时去清理,而孤儿进程是反的,父进程退出了,子进程到最后没人清理,就变成孤儿了,遇到这种情况,我们看看操作系统是怎么处理的

  1#include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 int main()
  6 {
  7     pid_t id=fork();
  8     if(id>0)
  9     {
 10         int cnt=5;
 11         while(cnt)
 12         {
 13             printf("我是父进程,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt--);
 14             sleep(1);
 15         }
 16         
 17         exit(0);
 18     }
 19     else if(id==0)
 20     {
 21 
 22         int cnt=15;
 23         while(cnt)
 24         {
 25             printf("我是子进程:pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt--); 
 26             sleep(1);
 27         }
 28 
 29     }
 30     return 0;
 31 }

在这里插入图片描述
通过上面的示例我们发现,我们的父进程退出之后,我们的子进程的父进程就变成1,我们来看看PID是1的进程是哪个程序:
在这里插入图片描述
这个1号进程正是我们的操作系统的进程,我们的操作系统领养了我们的子进程,
为什么要领养呢?为了方便子进程退出,有人给他清理资源
为什么bash补领养呢?因为bash只负责自己的子进程,没有能力领养。
相信此时大家对孤儿进程应该了解了吧

至此,值得关注的进程状态全部讲解完成

三、总结

到这里我们关于Linux上的进程都讲解完毕了,不知道同学们有没有收获,概念性比较多,但理解了就简单了,博主使用生动的小故事就是为了让大家可以更好的理解进程状态,希望大家可以可以都偶都支持博主,下篇我们开始介绍进程的优先级,也是一个非常关键的属性,希望大家到时候来支持博主,我们下篇再见

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/51259.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

更安全,更省心丨DolphinDB 数据库权限管理系统使用指南

在数据库产品使用过程中&#xff0c;为保证数据不被窃取、不遭破坏&#xff0c;我们需要通过用户权限来限制用户对数据库、数据表、视图等功能的操作范围&#xff0c;以保证数据库安全性。为此&#xff0c;DolphinDB 提供了具备以下主要功能的权限管理系统&#xff1a; 提供用户…

OpenMP

官方文档&#xff1a;OpenMP | LLNL HPC Tutorials OpenMP总览 统一内存访问&#xff1a;OpenMP、Pthreads 非统一内存访问&#xff1a;MPI OpenMP与Pthread OpenMP原理 串行区到达并行区后会派生多个线程&#xff0c;并行区代码执行完后进行线程合并&#xff0c;剩下主线程 编…

Linux - PostgreSQL 适用于9.x 以上的 tar.gz 源码安装与理解 - 报错集锦

这里写目录标题 序言主要内容bash 配置文件个人理解关于初始化 PostgreSQL 数据库的理解 启动方法检查服务器是否在PostgreSQL中运行关闭 postgresql 数据库方法参考链接 序言 PostgreSQL 9.x 以下版本笔者没用过&#xff0c;具体操作看参考链接&#xff0c;笔者就不记录重复操…

MODBUS-TCP转Ethernet IP 网关连接空压机 配置案例

本案例是工业现场应用捷米特JM-EIP-TCP的Ethernet/IP转Modbus-TCP网关连接欧姆龙PLC与空压机的配置案例。使用设备&#xff1a;欧姆龙PLC&#xff0c;捷米特JM-EIP-TCP网关&#xff0c; ETHERNET/IP 的电气连接 ETHERNET/IP 采用标准的 T568B 接法&#xff0c;支持直连和交叉接…

在centos 7系统docker上构建mysql 5.7

一、VM上已经安装centos 7.9&#xff0c;且已完成docker的构建 二、安装mysql5.7 安装镜像&#xff1a;[rootlocalhost lll]# docker pull mysql:5.7 查看镜像[rootlocalhost lll]# docker images 根据镜像id构建mysql容器&#xff0c;且分配端口号[rootlocalhost lll]# dock…

自定义view - 玩转字体变色

自定义View步骤&#xff1a; 1>&#xff1a;values__attrs.xml&#xff0c;定义自定义属性&#xff1b; 2>&#xff1a;在第三个构造方法中获取自定义属性&#xff1b; 3>&#xff1a;onMeasure【不是必须的】&#xff1b; 4>&#xff1a;onDraw&#xff1a;绘制代…

emacs打开git仓库下多个子工程的根目录问题解决案

emacs打开git仓库下多个子工程的根目录问题解决案 问题描述 如题所述&#xff0c;这个问题困扰我很久了&#xff0c;一直没搜到完整的解决方案。这次终于乘着空闲时间&#xff0c;研究了projectile.el源码找到了方案。 问题场景具体描述下: 我自己有一个私人git仓库&#x…

机器学习:GPT3

GPT3 模型过于巨大 GPT3是T5参数量的10倍&#xff01; 训练GPT3的代价是$12百万美元 Zero-shot Ability GPT3的思想是不是能拿掉Fine-tune 只需要给定few-shot或者zero-shot就能干相应的任务了。 few-shot learning&#xff08;no gradient descent&#xff09;&#…

(学习笔记)matplotlib.pyplot模块下基本画图函数的整理

matplotlib版本&#xff1a;3.7.1 python版本&#xff1a;3.10.12 基本函数 matplotlib版本&#xff1a;3.7.1python版本&#xff1a;3.10.12 1. plt.plot()函数1.1 plt.plot(x, y)1.2 plt.plot(x, y, **kwargs) 2. plt.xlable(), plt.ylable()3. plt.title()4. plt.show()5.p…

SkyWalking链路追踪-技术文档首页

SkyWalking 文档中文版&#xff08;社区提供&#xff09; (skyapm.github.io)https://skyapm.github.io/document-cn-translation-of-skywalking/ SkyWalking-基本概念 SkyWalking链路追踪是一个用于分布式系统的性能监控工具&#xff0c;它帮助开发人员了解系统中各组件之间…

向量vector模板输出、倒置、求和

运行代码&#xff1a; //向量vector模板输出、倒置、求和 #include"std_lib_facilities.h" //定义vector<double>的输入操作符>> istream& operator>>(istream& is, vector<double>& vv) {double dd0.0;if(is >> dd)vv.p…

【如何训练一个中英翻译模型】LSTM机器翻译模型部署之ncnn(python)(五)

系列文章 【如何训练一个中英翻译模型】LSTM机器翻译seq2seq字符编码&#xff08;一&#xff09; 【如何训练一个中英翻译模型】LSTM机器翻译模型训练与保存&#xff08;二&#xff09; 【如何训练一个中英翻译模型】LSTM机器翻译模型部署&#xff08;三&#xff09; 【如何训练…

Unity光照相关知识和实践 (烘焙光照,环境光设置,全局光照)

简介 本文将会通过一个简单的场景搭建&#xff0c;介绍如何使用烘焙光照以及相关的注意事项。另外还介绍了Unity内全局光照&#xff08;GI&#xff09;的知识和GI实际在游戏内的表现效果。 Unity关于光照相关的参考文档地址&#xff1a;https://docs.unity.cn/cn/current/Man…

Linux CentOS快速安装VNC并开启服务

以下是在 CentOS 上安装并开启 VNC 服务的步骤&#xff1a; 安装 VNC 服务器软件包。运行以下命令&#xff1a; sudo yum install tigervnc-server 输出 $ sudo yum install tigervnc-server Loaded plugins: fastestmirror, langpacks Repository epel is missing name i…

计算机论文中名词翻译和解释笔记

看论文中一些英文的简写不知道中文啥意思&#xff0c;或者一个名词不知道啥意思。 于是自己做了一个个人总结。 持续更新 目录 SoftmaxDeep Learning(深度学习)循环神经网络(Recurrent Neural Network简称 RNN)损失函数/代价函数(Loss Function)基于手绘草图的三维模型检索(Ske…

【笔记】PyTorch DDP 与 Ring-AllReduce

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 文内若有错误&#xff0c;欢迎指出&#xff01; 今天我想跟大家分享的是一篇虽然有点老&#xff0c;但是很经典的文章&#xff0c;这是一个在分布式训练中会用到的一项技术&#xff0c; 实际上叫ringallreduce。 …

用html+javascript打造公文一键排版系统8:主送机关排版

公文一般在标题和正文之间还有主送机关&#xff0c;相关规定为&#xff1a; 主送机关 编排于标题下空一行位置&#xff0c;居左顶格&#xff0c;回行时仍顶格&#xff0c;最后一个机关名称后标全角冒号。如主送机关名称过多导致公文首页不能显示正文时&#xff0c;应当将主送机…

redis的并发安全问题:redis的事务VSLua脚本

redis为什么会发生并发安全问题&#xff1f; 在redis中&#xff0c;处理的数据都在内存中&#xff0c;数据操作效率极高&#xff0c;单线程的情况下&#xff0c;qps轻松破10w。反而在使用多线程时&#xff0c;为了保证线程安全&#xff0c;采用了一些同步机制&#xff0c;以及多…

20.3 HTML 表格

1. table表格 table标签是HTML中用来创建表格的元素. table标签通常包含以下子标签: - th标签: 表示表格的表头单元格(table header), 用于描述列的标题. - tr标签: 表示表格的行(table row). - td标签: 表示表格的单元格(table data), 通常位于tr标签内, 用于放置单元格中的…

C语言枚举与联合体详解

本篇文章带来枚举与联合体相关知识详细讲解&#xff01; 如果您觉得文章不错&#xff0c;期待你的一键三连哦&#xff0c;你的鼓励是我创作的动力之源&#xff0c;让我们一起加油&#xff0c;一起奔跑&#xff0c;让我们顶峰相见&#xff01;&#xff01;&#xff01; 目录 一…