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

news2024/11/19 9:21:58


说在前面

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

本篇博主将通过从进程状态的广泛概念,深入到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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新建的普通用户无法使用sudo的问题

文章目录1.为什么新建用户无法使用sudo指令1. 查看sudoers的权限2. 切换成root用户解决问题1. 切换root用户2.进入 vim编辑器3. 配置成功1.为什么新建用户无法使用sudo指令 [lynVM-8-8-centos ~]$ sudo ls [sudo] password for lyn: lyn is not in the sudoers file. This i…

声学特征提取普及笔记

声学特征如何提取? 一、声学特征预处理 首先进行预处理,就是我们最后要提取一帧一帧的这种声学特征,这个语音信号经过预处理然后提取特征,那么特征也有用原始的傅里叶变换,STFT短时傅里叶变换得到这个语谱图特征,也有用FBANK就没有滤波器的输出,还有用MFCC。预处理包括…

SQL 通配符

通配符可用于替代字符串中的任何其他字符。 SQL 通配符 在 SQL 中&#xff0c;通配符与 SQL LIKE 操作符一起使用。 SQL 通配符用于搜索表中的数据。 在 SQL 中&#xff0c;可使用以下通配符&#xff1a; 通配符描述%替代 0 个或多个字符_替代一个字符[charlist]字符列中的…

Rabbitmq消息队列详解(三)——SpringBoot整合

SpringBoot整合 依赖&#xff1a; <!-- 加入rabbitmq --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency>配置&#xff1a; spring:application:nam…

【C初阶】C初阶考试题

选择加编程一、选择题&#xff08;一&#xff09;递归&#xff08;二&#xff09;后置发生死循环&#xff08;三&#xff09;后置运算&#xff08;四&#xff09;操作符运算&#xff08;五&#xff09;全局变量与生命周期&#xff08;六&#xff09;操作符知识&#xff08;七&a…

前端对接微信公众号网页开发流程,前期配置

微信公众号网页开发&#xff0c;其实就是我们开发的h5网页需要放到微信浏览器环境中使用&#xff0c;但是需要对接公众号授权&#xff0c;授权之后可以获取到用户的个人信息&#xff0c;以及可以使用公众号提供的一些API,如&#xff1a;图片上传、图片预览、获取位置信息、微信…

【Java异常】Java异常监控重要手段 --异常链

目录标题前言一、异常链介绍1.1 异常链概述1.2 Java中如何使用异常链二、Throwable1.1 Throwable中哪些API提供存储cause的功能1.2 Throwable中如何获取cause三、项目实战演练示例1:未存储cause示例2:存储cause两层嵌套示例3:存储cause三层嵌套四、总结前言 “异常链”无论是在…

构造题(agc059_b)

https://atcoder.jp/contests/agc059/tasks/ B - Arrange Your Balls Editorial / Time Limit: 2 sec / Memory Limit: 1024 MB Score : 700700 points Problem Statement You have NN balls of colors C_1, C_2, \ldots, C_NC1​,C2​,…,CN​. Here, all colors are rep…

引发C++程序内存错误的常见原因分析与总结

目录 1、概述 2、变量未初始化 2.1、变量未初始化的场景说明 2.2、对0xcccccccc、0xcdcdcdcd和0xfeeefeee等常见异常值的辨识度 3、空指针与野指针 3.1、空指针 3.2、野指针 4、线程栈溢出 5、内存越界 6、内存泄漏 7、堆内存被破坏 8、内存访问违例 8.1、访问64K…

7.Isaac教程--在Python中开发Codelets

在Python中开发Codelets 虽然就性能而言&#xff0c;编写小码的最佳语言是 C&#xff0c;但并非应用程序的所有小码都需要使用相同的语言。 Isaac SDK 还支持 Python codelets&#xff0c;或 pyCodelets&#xff0c;适合那些更熟悉 Python 的人。 本节向您展示如何执行以下操作…

可视化系列讲解:SVG绘制基本图形及如何复用

文章目录一、SVG坐标系二、SVG坐标系单位三、SVG绘制基本图形3.1 矩形3.2 圆形3.3 椭圆3.4 直线3.5 折线3.6 多边型3.7 路径3.8 文字3.9 图片四、SVG元素的组合五、图形元素定义复用和使用定义的复用5.1 defs与use5.2 symbol与use一、SVG坐标系 SVG 使用的坐标系统&#xff08;…

【Python】函数——传递任意数量的实参

传递任意数量的实参和传递任意数量的关键字实参 *args&#xff1a;表示用来接收任意数量的实参&#xff0c;其中&#xff0c;形参*args的星号会让Python创建一个名为args的空元组&#xff0c;并将接收到的任意数量的实参存储在这个元组中。**kwargs&#xff1a;表示用来接收任…

ARX给CAD发送命令的几种方法

本文迁移自本人网易博客&#xff0c;写于2015年11月16日。1、ads_queueexpr( _T("(command\"_POINT\" \"1,1,0\")") );该函数CAD未公开&#xff0c;使用时提前声明下就可以了。可以参考帮助文件中&#xff1a;Tips and Techniques 。2、acDocMan…

嵌入式:人机交互接口设计详解

文章目录键盘和LED的接口原理HD7279A与S3C2410A的连接原理图键盘和LED控制的编程实例LCD显示原理LCD控制器概述嵌入式处理器与LCD的连接S3C2410A的LCD控制器&#xff08;1&#xff09;STN LCD&#xff08;2&#xff09;TFT LCDLCD控制器的框图LCD接口信号STN LCD控制器操作&…

Java IO流 - 转换流的使用详细介绍

文章目录转换流字符输入转换流字符输出转换流转换流 之前我们代码编码和文件编码都是UTF-8, 所以没有出现中文乱码的问题 我们知道代码编码和文件编码的格式如果不一致的话会出现中文乱码的问题 那么如果在开发中, 我们确实会遇到编码不一致的情况如何解决呢? 我们可以使用字符…

【高阶数据结构】手撕红黑树(超详细版本)

&#x1f308;欢迎来到数据结构专栏~~手撕红黑树 (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort目前状态&#xff1a;大三非科班啃C中&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&#xff01;送给自己的一句…

JMS规范和AMQP协议

参考资料&#xff1a;《JMS与AMQP简述以及比较》《AMQP协议详解》《MQ消息队列的JMS规范和AMQP协议的区别》《消息队列之JMS和AMQP对比》写在开头&#xff1a;本文为学习后的总结&#xff0c;可能有不到位的地方&#xff0c;错误的地方&#xff0c;欢迎各位指正。一般情况下MQ的…

【数据结构与算法——C语言版】6. 排序算法(3)——插入排序

前言 在本系列的上两篇文章分别介绍了两种O(n2)的排序算法——选择排序和冒泡排序&#xff0c;今天是第三种O(n2)的排序算法&#xff1a;插入排序。 插入排序 核心思想 它的基本思想是将一个记录插入到已经排好序的有序表中&#xff0c;从而产生一个新的、记录数增 1 的有序…

软件测试~自动化测试Seleniums---1

一.什么是自动化测试 1.自动化测试介绍 自动化测试指软件测试的自动化&#xff0c;在预设状态下运行应用程序或者系统&#xff0c;预设条件包括正常和异常&#xff0c;最后评估运行结果。将人为驱动的测试行为转化为机器执行的过程。 将测试人员双手解放&#xff0c;将部分测…

机器视觉(十):印刷体字符识别

目录&#xff1a; 机器视觉&#xff08;一&#xff09;&#xff1a;概述 机器视觉&#xff08;二&#xff09;&#xff1a;机器视觉硬件技术 机器视觉&#xff08;三&#xff09;&#xff1a;摄像机标定技术 机器视觉&#xff08;四&#xff09;&#xff1a;空域图像增强 …