【Linux进行时】进程状态

在这里插入图片描述

进程状态:

❓假设我们在上课,在B站上上课,请问我们的B站是不是一直运行呢?💡不是的!

❓假设我们同时打开了B站和PDF阅读器时,是怎么运行的呢?

💡每一个进程在CPU跑一会,再从CPU拿下来放上另外一个上去,周而复始,这种叫做分时操作系统

❓那就有一个问题,假设先用B站,为什么先将B站这个进程放上去,而不是PDF阅读器呢?

💡这就取决于进程状态!

思维导图:

image-20230915173545002

1.进程的状态

1.1三种基本运行状态

  • 运行状态

🔥R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里

❓一个进程只要把自己放到CPU上开始运行了,是不是一直要到执行完毕,才把自己放下来?

💡不是,每一个进程都有一个叫做:时间片的概念! 其时间大概是在10 ms左右。所以并不是一个进程一直在执行,而是这多个进程在一个时间段内所有代码都会被执行 —— 这就叫做【并发执行】

所以呢这就一定会存在大量的进程被CPU放上去、拿下来的动作 —— 这就叫做【进程切换】

  • 并发and并行

🔥并行:指的是两个或者多个事件同一时刻发生(可以类比为一个公路,三台车不同道同向行驶)

🔥并发:指的是一段时间内有多个程序同时运行

  • 就绪状态

🔥指的是进程已经处于准备好执行的状态,但是CPU没有空闲的,

  • 阻塞状态和挂起状态

有两个概念:阻塞和挂起!

阻塞:进程因为等待某种条件就绪 ,而导致的一种不推进的状态——进程卡住了——阻塞一定在等待某种资源

就相当于进程太多了,卡着一个进程,在这个进程来看就是在等待CPU调度(某种资源)

🔥阻塞:进程等待某种资源就绪的过程

❓为什么阻塞呢?

💡进程要通过等待的方式,等具体的资源被别人是用使用完之后,再被自己使用。

❓什么是资源呢?💡资源=磁盘或者网卡显卡等各种外设(这是硬件,软件也有)

因为操作系统是通过先描述,后组织的方式来进行管理,假设用struct来代表这些外设用链表连接起来,

❓可以存在大量的进程吗?💡可以的❓要管理吗?💡先描述再组织

假设我们有一个进程task_struct要加载到cpu中,它在等待一个网卡资源

image-20230810113159424

CPU说你不能在我上面跑了,所以task_struct就添加到这个队列的尾部等待网卡这个资源

image-20230810114050941

也就是我们的task_struct在我们的列入到某种资源的队列当中,它就不会被CPU调度了吗,这不就是卡住了吗,不就是阻塞了吗!!!!

🔥pcb可以被维护在不同的队列中的!

阻塞:阻塞就是不被调度——一定是因为当前进程需要等待某种资源就绪——一定是进程task_struct结构体需要再某种被OS管理的资源下排队

挂起:

image-20230810151426838

📚例子

假设task_struct是个下载任务,这里突然没网了,CPU说这个task_struct就不能跑了,task_struct就链接在网卡这个队列的中,这里就是阻塞了

操作系统通过自己的一套算法,把占有内存的,不被调度的进程的数据和代码交换到磁盘当中

磁盘那边放了一份交换后的代码和数据,这里的内存的代码和数据被释放,

在被再次调度前再把代码和数据换回来就可以了

image-20230810152157573

🔥其中代码和数据由操作系统暂时将我们的从内存换到磁盘的过程中,此时这个进程就是挂起状态,全称叫做阻塞挂起状态

2.Linux进程状态

task_struct是一个结构体,内部会包含各种属性,包括状态(status)

为了研究 Linux 进程状态,我们把源码先拿出来看看:

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
  • R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
  • S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))
  • D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的
    进程通常会等待IO的结束。
  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

用0表示R,用1表示S,用2表示D,用4表示T,用8表示t,用16表示X,用32表示Z

  • 运行状态

❓进程只要是在R状态,就一定是在CPU上运行吗?💡不一定!

image-20230810153626277

所有运行的进程只要在运行的队列中排队就可以了,所以CPU调度进程只要去我们的队列中去挑进程就可以了

❓进程是什么状态?💡一般也看这个进程在哪里排队

进程状态查看我们可以用ps

这里我们也能拿 ps 指令来看进程的状态,我们开小窗输入:

ps axj | head -1 && ps axj | grep process | grep -v grep

image-20230810164739743

显然这里S是休眠状态

🔥首先需要声明一点,状态后面跟加号,表示是一个 **前台进程,**你只需要知道的是,能够在键盘上 Ctrl+c 暂停的都可以叫前台进程。

其实我们CPU的运行速度都很快,我们看到这里它一直在打印,其实是显示器(外设)一直在打印,CPU一瞬间就完成了,所以状态是S

我们将test.c中printf注释掉,再试一下

image-20230810165142801

image-20230810165055831

我们发现这里变成了R状态了

所以这个进程不访问任何资源,只等你 CPU,只要你被运行期间不访问外设,就不会被阻塞。

不访问外设,那么死也会在等待队列里,一直在等待队列中,这就让 process 达成 R状态!

🔥这里printf的本质就是向外设(网卡、显示器)打印消息,进程只要是R状态,并不直接代表进程正在运行,而代表该进程在运行队列中排队

image-20230915091533355

🔥队列由操作系统自己维护

  • 睡眠状态

S状态——休眠状态,可中断休眠,它一直在等待某种资源,其实就是阻塞状态

image-20230915093710034

🔥我们一般把 状态叫作 浅度睡眠,也叫做 可中断睡眠

  • 顾名思义,当进程处于 S 状态,它可以随时被唤醒。
  • 不仅仅是操作系统可以唤醒,你也可以唤醒,甚至你想杀掉它都行。
$ kill -9 [pid]

我们用另外一个例子来更直观感受S状态

#include <stdio.h>#include <unistd.h>int main(void){int a=0;printf("输入a的值:");scanf("%d",&a);printf("a=%d\n",a);                                        return 0;                                                                          }   

image-20230915095029316

将该进程运行起来我们可以看到其是出于S+的状态,因为【shell】此时正在等待用户的输入,这个就对应到了我们上面所讲到的 阻塞状态

🔥不仅如此,像我们一直在使用的bash,也可以算是一种【阻塞状态】,一直等待着我们去输入命令行,一旦有了的话它就进行读取

image-20230915095247760

  • 深度睡眠模式

这也是一种阻塞模式

"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */

这里D模式比S模式多一个disk,磁盘?那肯定跟磁盘有关系

一般而言,在 Linux 中,如果我们等待的是磁盘资源,我们进程阻塞所处的状态就是 D 状态。

与S状态类似,进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。
绝大多数情况下,进程处在睡眠状态时,总是应该能够响应异步信号的。否则你将惊奇的发现,kill -9竟然杀不死一个正在睡眠的进程了!于是我们也很好理解,为什么ps命令看到的进程几乎不会出现D状态,而总是S状态。

🔥 而TASK_UNINTERRUPTIBLE状态存在的意义就在于,内核的某些处理流程是不能被打断的。如果响应异步信号,程序的执行流程中就会被插入一段用于处理异步信号的流程(这个插入的流程可能只存在于内核态,也可能延伸到用户态),于是原有的流程就被中断了。

  • 暂停状态

T状态,暂停状态

我们先通过这个指令来了解一下,我们要使用的就是下面的18和19信号

kill -l

image-20230915110704336

进程暂停与进程休眠(阻塞) 没有关系,只是单纯不想让这个进程跑了。

比如有些进程在执行任务时,用户想让这个进程暂停一下,这其实很好理解。

比如看视频,听音乐,下载,都会有暂停。当你点击暂停的时候下载对应的代码就不跑了,此时这个进程你就可以认为是暂停状态。

kill -19 进程pid    暂停该进程
kill -18 进程pid    解除暂停

image-20230915111618657

kill -18 pid解除一下

  • 死亡状态

X状态,死亡状态

kill -9 PID

dead 代表死亡,所以 X状态对应的就是 死亡状态

这个没有什么好说的,X 状态的进程就代表死亡了,可以随时等待 OS 来收尸了。

  • 僵尸状态

当一个 Linux 中的进程退出的时候,一般不会直接进入X状态(死亡,资源可以立马被回收),而是进入Z状态

❓当进程退出后不直接变成X状态而是变成Z状态这是为什么呢?

💡当一个进程退出的时候,那最关心它的便是【父进程】。因为这个父进程费了很大的劲才将这个子进程fork出来,此时呢它突然挂掉了,那么此时父进程就必须去关心一下对应的子进程退出时的原因

在这个退出过程中,进程占有的所有资源将被回收,除了task_struct结构(以及少数资源)以外。于是进程就只剩下task_struct这么个空壳,故称为僵尸。
之所以保留task_struct,是因为task_struc t里面保存了进程的退出码、以及一些统计信息。而其父进程很可能会关心这些信息。

我们来造一个僵尸出来看看:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main(void) {pid_t id = fork();if (id == 0) {// childint cnt = 5;while (cnt) {printf("我是子进程,我还剩下 %ds\n", cnt--);sleep(1);}printf("我是子进程,我已经变僵尸了,等待被检测\n");exit(0);}else {// fatherwhile (1) {sleep(1);}}
}

image-20230915114258396

❓如果长时间处于僵尸状态,会有什么结果呢?

💡如果没有人收尸,该状态会一直维护,该进程的相关资源 (task_struct) 不会被释放!内存泄露!一般必须要求父进程进行回收,如何回收的问题我们会在进程控制章节讲解。

❓为什么要main()的返回值呢?💡return 0;这个是进程退出码

🔥如果-个进程退出了,立马X状态,立马退出,你作为父进程,有没有机会拿到退出结果呢? ? ? Linux当进程退出的时候,- -般进程不会立即彻底退出,而是要维持一个状态叫做Z, 也叫做僵尸状态— 方便后续父进程(OS)读取该子进程退出的退出结果!

只要父进程不退出,这个僵尸状态的子进程就一直存在。那么如果父进程退出了呢,谁又来给子进程“收尸”?
当进程退出的时候,会将它的所有子进程都托管给别的进程(使之成为别的进程的子进程)。托管给谁呢?可能是退出进程所在进程组的下一个进程(如果存在的话),或者是1号进程。所以每个进程、每时每刻都有父进程存在。除非它是1号进程。

1号进程,pid为1的进程,又称init进程。
linux系统启动后,第一个被创建的用户态进程就是init进程。它有两项使命:
1、执行系统初始化脚本,创建一系列的进程(它们都是init进程的子孙);
2、在一个死循环中等待其子进程的退出事件,并调用waitid系统调用来完成“收尸”工作;
init进程不会被暂停、也不会被杀死(这是由内核来保证的)。它在等待子进程退出的过程中处于S状态,“收尸”过程中则处于R状态。

  • 孤儿进程

如果父进程 一直存在,子进程退出了,父进程对子进程不管不顾,子进程退出后就要进入僵尸状态

如果有父子两个进程,因为一些问题父进程不存在了,子进程还没有退出呢?

myproc.c

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

make一下,没有问题

image-20230814144031956

这里的$@

和$^

$@代表冒号左侧的,红色的,目标文件

$^代表冒号右侧的,蓝色的,依赖文件

image-20230814144445334

while :;do ps ajx | head -1&&ps ajx |grep myproc | grep -v grep;sleep 1;echo "----------";done

image-20230814150123577

我们在旁边把程序运行起来

我们发现我们的父进程是5388 ppid 7666

子进程 5389 ppid5388

image-20230814150923186

后面父进程中止了,只剩下子进程

子进程是5389 ppid变成了1

image-20230814151026354

父进程这时候退出了那是不是应该处于僵尸状态呢?

这里我们为什么没有看到父进程处于僵尸状态呢?

我们在命令行中启动一个进程时,它的父进程是bash

父进程退出之后,它的父进程是bash(命令行解释器),所以这个父进程退出的时候,它的父亲帮他回收了

相当于是我死了,我爹bash帮我回收了

我们发现这个子进程的父进程死掉后,它给自己又找了个爹(1号进程),1好进程可以叫为操作系统

image-20230814152258685

image-20230814152355978

如果不领养会发生什么呢?

如果有一天这个子进程挂了,并且他没有父进程,他就会被操作系统遗忘,就一直处于一种占用操作系统内存空间的情况,也就是内存泄漏

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工业RFID进口品牌和国内品牌差距有多大?

随着国内的RFID技术也逐渐发展成熟&#xff0c;国产工业品牌也不断优化&#xff0c;推出了不少高品质、高性能的工业读写器。对于企业来说&#xff0c;在选择读写器的时候也有了更多的选择&#xff0c;那么&#xff0c;现如今工业RFID进口品牌和国内品牌差距有多大&#xff0c;…

深度解析NLP文本摘要技术:定义、应用与PyTorch实战

目录 1. 概述1.1 什么是文本摘要&#xff1f;1.2 为什么需要文本摘要&#xff1f; 2. 发展历程2.1 早期技术2.2 统计方法的崛起2.3 深度学习的应用2.4 文本摘要的演变趋势 3. 主要任务3.1 单文档摘要3.2 多文档摘要3.3 信息性摘要 vs. 背景摘要3.4 实时摘要 4. 主要类型4.1 抽取…

迅为i.MX8mm小尺寸商业级/工业级核心板

尺寸&#xff1a; 50mm*50mm CPU&#xff1a; NXP i.MX8M Mini 主频&#xff1a; 1.8GHz 架构&#xff1a; 四核Cortex-A53&#xff0c;单核Cortex-M4 PMIC&#xff1a; PCA9450A电源管理PCA9450A电源管理NXP全新研制配&#xff0c;iMX8M的电源管理芯片有六个降压稳压器、五…

C#-WinForm-发送邮件

登录QQ邮箱——设置——开启“POP3/SMTP服务” 登陆QQ邮箱→打开设置→开启“POP3/SMTP服务”&#xff0c;获取“授权码” 简单总结一下&#xff1a; 1、使用SmtpClient发送电子邮件是很简单的&#xff0c;只要正确创建了MailMessage对象和SmtpClient就可以很容易的发送出去电…

RBTree(红黑树)模拟实现(插入)

目录 红黑树的性质 红黑树的模拟插入 叔叔存在且为红色 叔叔不存在 旋转情况​​​​​​​ 叔叔存在且为黑色 总结 插入实现 节点 插入逻辑 左单旋 右单旋 红黑树是一颗平衡搜索二叉树&#xff0c;但是红黑树并不像 AVL 树一样是高度平衡二叉树&#xff0c;任意一…

无涯教程-JavaScript - LCM函数

描述 LCM函数返回整数的最小公倍数。最小公倍数是最小的正整数,它是所有整数参数number1,number2等的倍数。使用LCM添加具有不同分母的分数。 语法 LCM (number1, [number2] ...)争论 Argument描述Required/OptionalNumber1, number2... 您想要最小公倍数的1到255个值。 如…

kubesphere中间件部署

微服务部署前中间件部署 一、MySQL部署 1.1 使用Docker实现MySQL主从复制 docker run -p 3307:3306 --name mysql-master \ -v /mydata/mysql/master/log:/var/log/mysql \ -v /mydata/mysql/master/data:/var/lib/mysql \ -v /mydata/mysql/master/conf:/etc/mysql \ -e My…

Leetcode算法入门与数组丨3. 数组基础

文章目录 前言1 数组简介2 数组的基本操作2.1 访问元素2.2 查找元素2.3 插入元素2.4 改变元素2.5 删除元素 3 总结task03task04 前言 Datawhale组队学习丨9月Leetcode算法入门与数组丨打卡笔记 这篇博客是一个 入门型 的文章&#xff0c;主要是自己学习的一个记录。 内容会参…

带你熟练使用list

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

Nginx map 实现时间格式转换

哈喽大家好&#xff0c;我是咸鱼 最近我们需要把 Nginx 的日志接入到自研的日志采集平台上&#xff0c;但是这个平台只支持 JSON 格式&#xff0c;所以需要把 Nginx 日志格式改成 JSON 格式 例如下面这样的效果 刚开始在主配置文件 nginx.conf 中定义了一个名叫 json 的日志…

2023 蓝帽杯初赛web部分取证复现

前言&#xff1a;初赛进线下了&#xff0c;计划着在决赛前突击学习一下取证&#xff0c;但时间还是太紧 只看了很多内存取证和手机取证 计算机取证和服务器取证没掌握 ---( 不过复赛没考&#xff0c;也算狗运了) 目录 <1> web-LovePHP(file()函数侧信道攻击) <2&g…

在TensorFlow中使用GAN生成图像

一、说明 本文详细论述&#xff0c;如何在tensorflow下&#xff0c;在mnist数据集合上进行GAN实现。包括&#xff1a;框架建立、数据集读出、生成器、鉴别器、代价函数、优化等具体步骤的代码实现。 二、GAN框架介绍 生成器&#xff1a;此组件负责生成新图像。鉴别器&#xf…

《Docker与Kubernetes容器运维实战》简介

#好书推荐##好书奇遇季#《Docker与Kubernetes容器运维实战》已经出版。本书帮助读者系统掌握Docker与K8s运维技能。 本书内容 本书分两部分系统介绍Docker与Kubernetes的运维技术。 &#xff08;1&#xff09;Docker部分包括&#xff1a;全面认识Docker、初步体验Docker、Dock…

Vue记录(下篇)

Vuex getters配置项 *Count.vue <template><div><h1>当前求和为&#xff1a;{{$store.state.sum}}</h1><h3>当前求和的10倍为&#xff1a;{{$store.getters.bigSum}}</h3><select v-model.number"n"><option value&q…

HarmonyOS开发环境搭建

一 鸿蒙简介&#xff1a; 1.1 HarmonyOS是华为自研的一款分布式操作系统&#xff0c;兼容Android&#xff0c;但又区别Android&#xff0c;不仅仅定位于手机系统。更侧重于万物物联和智能终端&#xff0c;目前已更新到4.0版本。 1.2 HarmonyOS软件编程语言是ArkTS&#xff0c…

有哪些编程语言能在AI的应用上大显身手?

人工智能&#xff08;AI&#xff09;是当今最热门的技术领域之一&#xff0c;它涉及到许多不同的子领域&#xff0c;如机器学习、深度学习、自然语言处理、计算机视觉、语音识别等。要开发AI应用&#xff0c;就需要使用一种或多种编程语言&#xff0c;但是&#xff0c;并不是所…

函数式编程汇总

目录 一 . Lambda 表达式 实例 省略规则 二. Stream 流 案例数据准备 入门实例 调试技巧 常用操作 创建流 1. 单例集合 2. 数组 3. 双列集合 中间操作 1. filter 2. map 3. distinct 4. sorted 5. limit 7. flatMap 终结操作 1. forEach 2. count 3. max…

再战SDRAM与资料整理。

总之只要阅读操作手册&#xff0c;按照时序来&#xff0c;完全不难&#xff01; 器件记录&#xff1a; 小梅哥AC620上SDRAM&#xff1a;M12L2561616A-6TG2T 其的存储空间为16M*16256MB&#xff0c;第二行的数字则与其速度等级有关&#xff1b;其分为&#xff1a; 4bank*16bit…

ES6的代理模式 | Proxy

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 正文 语法 Handler 对象常用的方法 handler.get 可撤消的Proxy Proxy的应用场景 校验器 私有属性 为什么要…

【eXtplorer】本地搭建免费在线文件管理器并实现在外远程登录

文章目录 1. 前言2. eXtplorer网站搭建2.1 eXtplorer下载和安装2.2 eXtplorer网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1. 前言 通过互联网传输文件&#xff0c;是互联网最重要的应用之一&#xff0c;无论是…