Linux系统 —— 进程系列 - 进程状态 :僵尸与孤儿
目录
1. 进程状态的概念
1.1 课本上的说法:名词提炼
1.2 运行,阻塞和挂起
1.2.1 什么叫做运行状态(running)?
1.2.2 什么叫做阻塞状态(sleeping)?
1.2.3 什么叫做挂起状态(pending)?
2. linux下的进程状态
2.1 R运⾏状态(running)
2.2 S睡眠状态(sleeping)
2.3 D磁盘休眠状态(深度睡眠)(Disk sleep)
2.4 T/t暂停状态(stopped)
2.5 X死亡状态(dead)
2.6 Z僵尸状态(zombie)
如何模拟Z状态
僵尸进程危害
浅谈
3. 孤儿进程
接前文:Linux系统 —— 进程系列 - 进程的概念,PCB与PID和fork-CSDN博客
https://blog.csdn.net/hedhjd/article/details/144299919?spm=1001.2014.3001.5501
1. 进程状态的概念
⼀个进程可以有多个状态(在Linux内核⾥,进程有时候也叫做任务),打个比方:我们现在正在上课,这叫做上课中,上完课回到宿舍睡觉,这叫做休息中,休息完跑到操场是跑步,这叫做运动中
所以每一个人都有自己对应的状态,状态决定了我们当前正在做什么事情,以及系统应该如何看待我们:比如你每天准时上课,那么你就是一个好学生
对于进程来说,这个进程当前是需要被使用,还是正在休眠,正在等待,所以进程的状态决定了当前进程在系统里应该被如何处理
进程状态的本质其实就是task_state结构体内部的一个整数
1.1 课本上的说法:名词提炼
由上图可以得知:进程具有多种状态,状态之间是可以相互转化的
1.2 运行,阻塞和挂起
PCB即属于双链表又属于队列,但是我们可以把队列也看作是一个双链表,只不过这个双链表遵守的是尾进头出
在这里有一个既不属于Linux也不使用其他操作系统的调度算法之一的 —— FIFO(先进先出),也就是说在这个队列当中在头部的优先级高,尾部的优先级低,优先级按照顺序排
我们下面这张图就是CPU调度按照顺序来依次调度
1.2.1 什么叫做运行状态(running)?
当一个进程只有CPU在跑的时候,它就是运行状态,但是,在当代计算机里面,只要一个进程在调度队列当中,它就是运行状态(running)
处于running状态的进程,也么是正在被运行,要么就是已经准备好了,随时都可以被调度
运行状态对于的是创建,就绪和运行,其中运行和就绪可以当作一种状态
1.2.2 什么叫做阻塞状态(sleeping)?
举个例子:C语言当中的scanf函数,当我们scanf的时候,其实我们并不是在等待用户输入内容,而是在等待键盘硬件就绪,也就是在等待键盘上有按键被按下了,如果没有被按下就称之为键盘不就绪,那么scanf就要等
阻塞就是等待某种设备或者资源就绪,在等待的期间如果一直不就绪,那么我的进程就不会被调动,那么就会卡在哪里不动
我们以一个问题来理解一下:操作系统os是怎么对软硬件进行管理的?答案是:先描述,再组织
我们先拿硬件来举例子:实际上,因为操作系统要管理硬件,所以操作系统os也要创建数据结构(struct_device)
这个数据结构里包含的就是目标设备的所有属性,那么就说明struct_device可以直接或者间接获得我们对应的数据
上面这张图可以称之为设备队列,而下面的图片叫做运行队列
我们都知道,在内存当中,每一种设备都要对应一种struct_device结构体,当我们读磁盘读网卡的时候如果设备上对应的设备没有就绪,那么我们的进程就要阻塞等待了,那么在操作系统中我们如何理解阻塞等待呢?我们可以在数据结构体里加上一个等待队列
所以我们对应的每一个设备它都有一个等待队列
我们假设我们的CPU正在运行,当运行的时候执行我们的代码(假设是scanf)需要就绪读取,读取的时候OS发现需要去读取键盘,然后OS去检查键盘的状态,然后发现键盘没有任何活跃的状态,那么你这个进程无法读到键盘的任何数据进程就无法继续执行了,所以操作系统把这个进程从cpu上拿下来啊,并且把这个进程从运行队列当中移走然后把它链入到我们对应的特定设备的等待队列当中,那么这个进程就不会再被调度了,那么这个进程此时就处于阻塞状态
只有在运行队列里的进程才会被CPU调度,不在运行队列里转而在设备队列里等待,那么这个进程就叫做阻塞
1.2.3 什么叫做挂起状态(pending)?
当我们有一个进程处于阻塞状态的时候, 如果这个时候又来了几个进程, 而这个时候操作系统的内存不足了,那么这个时候, 操作系统就需要在保持正常的情况下节省出来内存资源
而我们知道一个进程如果在阻塞状态, 那么它的代码和数据就是处于一个空闲的状态。 这个时候操作系统就会将进程的PCB保留, 而进程的代码和数据就会被放到外设当中
当下次资源就绪的时候,进程就会被重新唤醒。 那么这个时候代码和数据再次从磁盘放到内存中!而这个过程就叫做换出和换入操作,而换出后, 也就是代码和数据在磁盘时, 就叫做挂起状态,这种挂起状态称为阻塞挂起状态,那么当它换入时,我们就可以将阻塞挂起状态重新改为运行状态,那么该进程就可以程序被调度了
2. linux下的进程状态
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 */
};
2.1 R运⾏状态(running)
运行状态并不意味着进程⼀定在运⾏中,它表明进程要么是在运⾏中要么在运⾏队列⾥
我们先简单创建个代码
运行结果
我们再打开一个xshell来查看一下我们的进程
我们再给一个命令让它一直跑起来,每隔一秒查一次
但是我们就发现了,为什么进程里面都是S呢?答案就是因为我们的代码里面有prinft函数,如果进程运行需要1秒的话,假设prinft函数运行需要1纳秒,那么1秒减去1纳秒剩下的时间进程就在等待IO,所以就是S状态,所以我们当前这个进程正在运行队列和等待队列来回切换,也就是正在阻塞状态
解决方法就是将printf去掉, 那么就不用打印到外设上, 就不需要等待。 我们再查看进程状态, 进程的状态就是R运行了
我们可以看到图中的R后面还有一个 + ,这个 + 的意思是我们的确这个进程启动是在前台启动的
"R (running)", /*0 */
我们可以看到,R为0,那么我们只需要在PCB当中将当前状态设置为对应的整数就可以保证为R
"S (sleeping)", /*1 */
同理S为0,那么我们也只需要在PCB当中将当前状态设置为对应的整数就可以保证为S,其他的几个状态也是如此
2.2 S睡眠状态(sleeping)
睡眠状态意味着进程在等待事件完成(这⾥的睡眠有时候也叫做可中断睡眠(interruptible sleep))
在Linux当中,操作系统理论里我们的阻塞状态叫做阻塞,而在Linux内核当中,我们的阻塞状态叫做S,我们看到一个进程卡住不动了,其实就是这个进程当前没有被调度,这个进程正在等待键盘有数据,所以这个状态叫做阻塞状态
2.3 D磁盘休眠状态(深度睡眠)(Disk sleep)
"D (disk sleep)", /*2 */
深度睡眠状态有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束 ,也叫深度睡眠,其实也是一种阻塞状态,我们前面的S也叫做浅度睡眠
浅度睡眠状态也叫做可中断休眠状态,简单来说就是:如果一个进程处于S状态,那么我们可以直接把这个进程杀掉,这个进程会响应我们杀掉它的动作
深度睡眠其实就是一种不响应操作系统任何请求的状态, 一般的阻塞状态, 当进程停止等待外设后就会进入运行状态, 但是深度睡眠只有当完成了特定的任务, 否则不会响应操作系统的任何命令, 即便系统关机了, 这个进程仍然会自己跑
D状态产生的原因是因为进程向磁盘中写入数据,如果我们想要将1G数据写到磁盘中,但是对于磁盘来说, 磁盘写入数据是有可能失败的(磁盘满了或者其他原因), 所以对于进程来说, 他写入数据就不能将数据交给磁盘后不管了, 他要等待磁盘写入的结果。 如果没有写入成功, 可以再写入一次, 或者写入不成功后想其他办法处理数据
那么进程就将数据交给磁盘,但是对于进程来说这个期间等待的时间是非常长的,如果这个时候内存满了, 操作系统管理内存, 就势必要杀掉一部分进程,这个过程是必须等
而我们的进程在等待磁盘的过程中会处于闲置的状态, 那么就容易被操作系统杀掉,而被操作系统杀掉后, 磁盘就不会找不到进程, 那么他就不会在进程写入数据了(数据丢失)所以, 为了避免这种情况, 就出现了深度睡眠——D状态,只要进程处于D状态,那么这个进程就不可能被杀掉,即便操作系统关机, 只要电源存在, 就可以一直进入,想要结束D状态,只有关掉电源
D状态其实也是一种阻塞状态
2.4 T/t暂停状态(stopped)
"T (stopped)", /*4 */ "t (tracing stop)", /*8 */
暂停状态(stopped)可以通过发送 SIGSTOP 信号给进程来暂停(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行
暂停状态属于Linux的一种特有状态
t是有特殊用途的,主要是用来做debug的
2.5 X死亡状态(dead)
"X (dead)", /*16 */
死亡状态(dead)这个状态只是⼀个返回状态,你不会在任务列表里看到这个状态
死亡状态其实对应的就是我们系统中的结束状态
2.6 Z僵尸状态(zombie)
"Z (zombie)", /*32 */
1. 僵死状态(Zombies)是⼀个⽐较特殊的状态。当进程退出并且⽗进程(使⽤wait()系统调⽤,后⾯讲)没有读取到⼦进程退出的返回代码时就会产⽣僵死(⼫)进程
2. 僵死进程会以终⽌状态保持在进程表中,并且会⼀直在等待⽗进程读取退出状态代码
3. 所以,只要⼦进程退出,⽗进程还在运⾏,但⽗进程没有读取⼦进程状态,⼦进程进⼊Z状态
举个例子:比如有一天我们在路上走路,然后我们看到有一个人躺在路边,我们靠近之后发现这个人已经走了好一会了,然后我们就报警打110,警察来了之后就开始封锁现场,警察过来的时候可能还要把法医带过来,然后在这个人身上做一些采样拿回去做化验拿几根头发,什么的,用于判断这个人是自杀还是谋杀还是自然死亡,当法医查完之后,他把在这个人身上获取了法医想获取的有效信息之后,法医就说可以撤了。这个时候呢我们警察才会通知家属啊,准备后事,然后就把人就拉走了
那么在他死亡之后到被抬走之前这段时间这个人一直在地上躺着,那么这个人在这段时间里所处的状态叫做僵尸状态,为什么要让这个人处于僵尸状态呢?,是为了获得这个人死亡(退出)时的死亡信息(自杀还是谋杀还是自然死亡),当这个人被警察抬走的时候就变成了X状态
//创建维持30秒的僵死进程例⼦ #include <stdio.h> #include <stdlib.h> int main() {pid_t id = fork();if (id < 0) {perror("fork");return 1;}else if (id > 0) { //parentprintf("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状态
我们模拟Z状态的前提条件是我们必须得有父子进程,而且要让这个子进程在退的时候,父进程什么都不干,我们先暂时先不讲父进程怎么解决僵尸状态,我们只需要父进程什么都不管,然后子进程直接退出,如果我们也不获取子进程的退出的信息,那么子进程就必须一直把自己维持在Z状态
就好比在路边啊,一个人倒下了那么打110没人来获取这个人的退休结果信息,那么此时,这个人就只能一直在路边躺着,所以我要模拟验证Z状态,我们就要创建父子进程,让Z进程在一定程度上直接退出,子进程退出之后我们就可以查到我们子进程的相关信息了
观察上面的两张图片,我们发现前面子进程还在正常运行,但是后面就只剩下一个父进程了,观察我们状态的那张图片,我们发现状态里有Z状态
以上这个情况就是说, 对于一个进程来说, 它在退出的时候, 一定要维持一段时间的僵尸进程, 而只有当父进程或则其他关系进程子进程的资源将这个进程的情况读取到了, 才会去释放这个子进程的资源。 也就是说, 对于僵尸进程来说, 如果父进程一直不去释放它, 那么它就会一直占用着资源,也就导致了内存泄漏
僵尸进程危害
1. 进程的退出状态必须被维持下去,因为他要告诉关⼼它的进程(⽗进程),你交给我的任务,我办的怎么样了。可⽗进程如果⼀直不读取,那⼦进程就⼀直处于Z状态?是的!
2. 维护退出状态本⾝就是要⽤数据维护,也属于进程基本信息,所以保存task_struct(PCB)中,换句话说,Z状态⼀直不退出,PCB⼀直都要维护?是的!
3. 那⼀个⽗进程创建了很多⼦进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本⾝就要占⽤内存,想想C中定义⼀个结构体变量(对象),是要在内存的某个位置进⾏开辟空间
浅谈
我们目前所讲到的6种状态其实都是某一个进程的子进程,可能是我们自己进程的子进程,也有可能是bash进程的子进程
3. 孤儿进程
如果一个父进程先退出,那么子进程就会被操作系统领养,子进程的父进程会变成操作系统,这个时候子进程就称之为孤儿进程,这个过程就叫做领养
为什么需要领养操作?答案是一个进程想要被释放, 就需要父进程,如果没有父进程的话,子进程本身是一个进程,它也需要被释放, 否则就会发生内存泄漏, 所以就需要被领养
如果父进程被终止, 子进程仍然会运行
完结撒花~
相关文章:

Linux系统 —— 进程系列 - 进程状态 :僵尸与孤儿
目录 1. 进程状态的概念 1.1 课本上的说法:名词提炼 1.2 运行,阻塞和挂起 1.2.1 什么叫做运行状态(running)? 1.2.2 什么叫做阻塞状态(sleeping)? 1.2.3 什么叫做挂起状态&…...

linux/centOS7用户和权限管理笔记
linux系列中可以: 配置多个用户配置多个用户组用户可以加入多个用户中 linux中关于权限的管理级别有2个级别,分别是: 针对用户的权限控制针对用户组的权限控制 一,root用户 root用户拥有最大的系统操作权限,而普通…...

使用C#基于ADO.NET编写MySQL的程序
MySQL 是一个领先的开源数据库管理系统。它是一个多用户、多线程的数据库管理系统。MySQL 在网络上特别流行。MySQL 数据库可在大多数重要的操作系统平台上使用。它可在 BSD Unix、Linux、Windows 或 Mac OS 上运行。MySQL 有两个版本:MySQL 服务器系统和 MySQL 嵌入…...
Scala函数的泛型
package hfd //泛型 //需求:你是一个程序员,老板让你写一个函数,用来获取列表中的中间元素 //List(1,2,3,4,5)>中间元素的下标长度/2 >3 //getMiddleEle object Test38_5 {def print1():Unit{println(1)}def print2(): Unit {println(…...

云轴科技ZStack亮相中国生成式AI大会上海站 展现AI Infra新势力
近日,以“智能跃进,创造无限”为主题的2024中国生成式AI大会在上海举办。本次大会由上海市人工智能行业协会指导,智东西、智猩猩共同发起,邀请了人工智能行业的顶尖嘉宾汇聚一堂,以前瞻性视角解构和把脉生成式AI的技术…...
态感知与势感知
“态感知”和“势感知”是两个人机交互中较为深奥的概念,它们虽然都与感知、认知相关,但侧重点不同。下面将从这两个概念的定义、区分以及应用领域进行解释: 1. 态感知 态感知通常指的是对事物当前状态、属性或者内在特征的感知。它强调的是在…...

汽车零部件设计之——发动机曲轴预应力模态分析仿真APP
汽车零部件是汽车工业的基石,是构成车辆的基础元素。一辆汽车通常由上万件零部件组成,包括发动机系统、传动系统、制动系统、电子控制系统等,它们共同确保了汽车的安全、可靠性及高效运行。在汽车产业快速发展的今天,汽车零部件需…...

谷歌浏览器的网页数据导出与导入方法
谷歌浏览器是全球最受欢迎的网络浏览器之一,它不仅提供了快速、安全的浏览体验,还拥有丰富的功能和扩展程序。本文将详细介绍如何在Chrome浏览器中导出和导入网页数据,同时涵盖一些相关的实用技巧,如调试JavaScript、自动填充表单…...

pytroch环境安装-pycharm
环境介绍 安装pycharm 官网下载即可,我这里已经安装,就不演示了 安装anaconda 【官网链接】点击下载 注意这一步选择just me 这一步全部勾上 打开 anaconda Prompt 输入conda create -n pytorch python3.8 命令解释:创建一个叫pytorch&…...
【大模型】PostgreSQL是向量数据库吗
PostgreSQL(通常简称为 Postgre)本身并不是一个专门的向量数据库,但它可以通过扩展或插件支持向量数据的存储、检索和处理,因此可以在某些场景下作为向量数据库使用。以下是关于 PostgreSQL 是否可以作为向量数据库的详细说明&…...

【PyQt5教程 一】Qt Designer 安装及其使用方法说明,附程序源码
目录 一、PyQt5介绍: (1)PyQt简介: (2)PyQt API: (3)支持的环境: (4)安装: (5)配置环境变量…...

Qt 联合Halcon配置
文章目录 配置代码窗口绑定 配置 选择添加库 选择外部库 LIBS -LC:/Program Files/MVTec/HALCON-17.12-Progress/lib/x64-win64/ LIBS -lhalconcpp\-lhdevenginecpp\-lhalconINCLUDEPATH C:/Program Files/MVTec/HALCON-17.12-Progress/include DEPENDPATH C:/Program Fil…...
Vue导出报表功能【动态表头+动态列】
安装依赖包 npm install -S file-saver npm install -S xlsx npm install -D script-loader创建export-excel.vue组件 代码内容如下(以element-ui样式代码示例): <template><el-button type"primary" click"Expor…...
C#调用python 程序
需要通过nuget安装ironphthon using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Win…...

day11 性能测试(4)——Jmeter使用(黑马的完结,课程不全)
【没有所谓的运气🍬,只有绝对的努力✊】 目录 1、复习 1.1 断言(3种) 1.2 关联(3种) 1.3 录制脚本 2、Jmeter直连数据库 2.1 直连数据库——使用场景 2.2 直连数据库——操作步骤 2.2.1 案例1&…...

机器学习详解(4):多层感知机MLP之理论学习
文章目录 1 MLP知识引入1.1 深度学习的发展1.2 神经元(Neuron)1.3 感知机(Perception)1.3.1 介绍1.3.2 感知机在二分类中的应用1.3.2.1 理论1.3.2.2 感知机计算实例 1.3.3 感知机总结 2 MLP(Multilayer Perceptron)2.1 介绍2.2 反向传播2.2.1 实例2.2.2 反向传播计算实例 3 总结…...

【C++】类中的特殊成员——静态成员,友元成员,常量成员
下图为笔者根据自己的理解做的图,仅供参考~ 文章目录 一.静态成员static*类外 1.1静态数据成员1.2静态函数成员*不同属性下的静态成员 1.3局部静态(Local Static) 二.常量成员2.1常量数据成员2.2常量函数成员2.3常量对象 三.友元成员3.1友元函数3.2友元类友元的特…...

开源 Agent 小屋
知乎:何枝地址:https://zhuanlan.zhihu.com/p/9096314010 Live Demo(网站在进入前可能会加载一段时间,需要等一等) 人物观测:Agent Life Live Demo[1] 行为统计:Agent Life Action Logging Bo…...
Mina之账户模型
为了能真正提升自己的能力,而不是机械低效的Ctrl C / Ctrl V,先从基本概念入手,利用ChatGPT来弄懂Mina。 Mina Mina Protocol 是一种轻量级区块链,被称为“世界上最轻的区块链”。其目标是通过极小的链上数据大小和强大的隐私…...
STM32 ADC 配置
ADC(模数转换器)用于将模拟信号转换为数字信号,以便单片机处理。 模数转换器(Analog-to-Digital Converter, ADC)是电子系统中不可或缺的一部分,它负责将现实世界中的连续物理量,如温度、声音、…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...