说在前面

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

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

    PyCharm到期了,所以打算换成VS Code(宇宙最好用编辑器?)试一试.但是下载之后不太会配置,网上不少的文章也比较旧了,所以打算自己看着官方教程配置一下.(VSCode版本:1.49.2,Py ...

  2. win10系统怎么修改host文件

    1.先根据下面路径找到host文件 C:\Windows\System32\drivers\etc 2.把HOST文件复制一份出来 3.修改完成后,直接替换就可以

  3. 深度学习(三)——Transforms的使用

    一.Transforms的结构及用法 导入transforms from torchvision import transforms 作用:图片输入transforms后,可以得到一些预期的变换 1. ...

  4. el-table 暂无数据自定义

  5. 无法连接uniCloud本地调试服务,请检查当前客户端是否与主机在同一局域网

  6. vue-cli3.x中public和assets的区别

    今天开发了一个html5视频播放功能. vedio.mp4资源放在public文件夹下.那vue-cli3.x中public和assets的区别 vue-cli3.0有两个放置静态资源的目录分别是pu ...

  7. 8. exporter

    一.已经实现的收集器 1.1 可收集的内存指标 1.2 可收集的jetty指标 二.自定义收集 2.1 summer 2.2 histogram 三.架构设计 exporter作为Prometheus ...

  8. Verilog Review

    Agenda 目的 Verilog概述 Verilog建模 模块 模块组成 书写建议 时延 Verilog基本语法 标识符 可读性 注释 空格 数据类型 操作数 运算符 条件语句 循环语句 函数 Ve ...

  9. Go-强制类型转换-T(x)

    类型转换 T(x) 具有相同的底层类型 数字类型之间可以互相转换(int系 uint系 float系),较大数转换成较小数会损失精度 字符串与切片之间的转换 string <==> []r ...

  10. AspNetCore在docker里访问Oracle数据库的坑:ORA-01882: timezone region not found

    哦吼 之前刚说了尝试了使用docker来部署AspNetCore应用,结果这才刚上班就遇到问题了= =- 我这项目用的数据库是Oracle,之前直接运行没啥问题,但放在docker里运行就报了这个错误 ...