【Linux】进程状态(二)
目录
前言:
一、进程状态:
1.运行状态(时间片)
2.阻塞状态
3.阻塞挂起状态
二、Linux进程状态:
1.运行状态(R)和阻塞状态(S)
2.深度睡眠状态(D)
3.停止状态(T)
3.1使进程在后台运行
4.追踪暂停状态(t)
5.死亡状态(X)和僵尸状态(Z)
5.1进程退出信息
三、孤儿进程:
四、命令总结:
总结:
前言:
我们已经知道了进程的一些属性,和如何创建子进程,那么接下来我们需要了解更多关于进程的概念。
一、进程状态:
我们主要讲述Linux的进程状态。
我们先来了解什么是并行和并发。
并发是指多个任务或者事件在一段时间内交替执行。它强调的是在宏观上看起来这些任务是同时在进行,但在微观层面,实际上在某个瞬间可能只有一个任务在执行。还是用交通来类比,在一个单车道的道路上,有多辆车(任务)需要通过。由于只有一个车道,车辆不能同时通过,但是通过合理的调度,让每辆车都有机会前进,在一段时间内,看起来所有的车辆都在前进。例如,在一个单核处理器的计算机系统中,同时运行多个程序。由于只有一个核心,这些程序不能真正同时执行。操作系统会在这些程序之间快速切换,在一段时间内,每个程序都能得到执行时间,就好像它们在同时运行一样。
并行是指多个任务或者多个事件在同一时刻同时执行。这就好比有多个车道的高速公路,不同的车辆(任务)可以在不同的车道上同时前进,它们在物理时间上是重叠的。例如,在一个拥有多核处理器的计算机系统中,不同的核心可以同时处理不同的计算任务。假设我们有一个四核处理器,当执行四个独立的计算任务(如对四个不同的数据集进行数学运算)时,这四个任务可以同时在四个核心上运行,它们真正地在同一时间点都在执行,这就是并行处理。
Linux/Windows民用级别的操作系统,都是分时操作系统(调度追求公平)。
实时操作系统,实时操作系统一般要将一个特定的进程彻底执行完(在特定的领域会使用),不追求调度公平。
操作系统内会提供一个runqueue的运行队列:
而我们一般就是并发,也就是这样:
1.运行状态(时间片)
所以我们在理解运行状态时,就是当进程在运行队列中,该进程就处于运行状态。
此时CPU调度进程时,直接在runqueue队列中拿到一个进程的PCB即可。之后在CPU上运行完以后(也就是该进程的时间片到达以后),直接根据FIFO算法(先进先出)将时间片到达的进程再尾插到进程链表最后即可。
2.阻塞状态
操作系统有时如何管理硬件的呢?——先描述,在组织!
struct device
int type;
//比如1代表键盘
int status;//状态
//管理时间
//其他属性
}struct device
{int type;//比如1代表键盘int status;//状态//管理时间//其他属性
}
此时如果有代码执行到了scanf时,CPU不可能一直让其在CPU上等待。其实struct device结构体中还有一个属性就是task struct* wait_queue:
所以当代码运行到scanf时,用户没有输入时,就会把该进程放入该设备的wait_queue中等待。当用户输入数据后,会再把该进程链入到runqueue中。
当进程在键盘的等待队列中,也被称为阻塞状态。所以进程都是在队列中的,状态只是看在那些队列中而已。
运行和阻塞的本质就是让不同的进程处在不同的队列中。等待的本质:链入目标外部设备,CPU不调度。
3.阻塞挂起状态
因为即使在等待队列中,也会占据内存,可此时内存已经严重不足了。此时操作系统为了自身的安全,会把该进程代码和数据换出到磁盘中,当然PCB还保留着。对于阻塞的进程,此时该用户又输入了内容,但是阻塞状态都是运行状态给定的,所以会直接把该进程再链入到运行状态的队列中,此过程为换入。
磁盘中有一个专门为此存在的分区——swap分区。当有很多这样处于阻塞的进程,操作系统内存严重不足时,可能会把所有处于阻塞状态的进程都换出到swap分区上。
以上是阻塞挂起状态。当然还有运行挂起,也就是正在运行时的进程加载到swap分区中。但是这个风险较大,一般操作系统不会开启。
这个过程就会变慢,也就是时间换空间。swap分区一般设计为内存的等量大小,根据工程师分配。
一般云服务器swap功能会被禁用,系统一般对时间要求更高。如果此时操作系统内存快要占满,就会杀死正在运行的进程以保证自身安全,这也就是我们有时可能会遇到的闪退。
二、Linux进程状态:
我们之前说的都是进程的状态,但是接下来我们要说的是Linux进程的状态:
1.运行状态(R)和阻塞状态(S)
我们写一个代码:
#include<stdio.h>int main()
{int cnt = 0;while(1) {printf("hello world, cnt: %d\n", cnt++);}return 0;
}
运行该进程,在另外一个窗口中查看该进程的运行状态:
此时可以看到我们有时能查到S状态,有时能查到R状态(后面的+是指的在前台下跑的)。这是为什么?
其实S状态就是阻塞状态。你可能不相信,此时我们把代码更改一下:
#include<stdio.h>int main()
{int cnt = 0;while(1) {scanf("%d", &cnt);printf("hello world, cnt: %d\n", cnt);}return 0;
}
此时我们再修改代码,此时我们先把打印语句给注释掉再次观察状态:
此时为运行状态。 这是为什么?
一个进程的时间片是非常短的,而print是往显示器中写的,也就是IO,所以大部分时间都是阻塞状态,之后偶尔是R状态。
加入你使用的是云服务器,所以还要从你服务器所在地传入到你所在的地方,也就是网络IO,所以你可能会很难查到R状态。
在阻塞状态的进程,可以被kill发送信号给杀掉。这种可中断睡眠也称为浅睡眠。
2.深度睡眠状态(D)
阻塞等待状态的一种,不可中断睡眠,深度睡眠。
此时有10w条银行数据,需要往磁盘中写入,进程A会处于阻塞状态,知道在磁盘中写完这些数据。此时内存资源严重不足了,操作系统把这个进程A给干掉了。此时磁盘在写入第8w条数据时出现了错误,于是向进程A汇报错误,结果进程A已经挂掉了,于是磁盘就把这些数据清空了。
此时就出现了问题,因为这10w条数据很重要,于是操作系统就把向磁盘中写入数据进程状态的阻塞又分出了一种D状态,也就是不可终止的深度睡眠状态。
这里不做演示。当在公司中看到该状态,有两种可能:
- 磁盘可能要挂掉了,磁盘空间不足或者磁盘老化了
- 操作系统可能要挂掉了
3.停止状态(T)
我们再次修改code.c代码,让其死循环打印:
这里相当于发送暂停信号。 之后再对其发送-18SIGCONT继续信号:
可以看到刚才停止的程序又继续运行了。这时我们在程序运行的Xshell窗口上Ctrl+C发现无法终止程序,你可能也发现了,当我们查看code这个运行程序时,发现状态栏后面的+消失了,之前说过,这里的+代表在前台运行,此时已经转到后台运行了,而Ctrl+C只能杀死前台运行的程序,所以此时只能通过信号终止进程。
发送-9信号杀死code程序。
3.1使进程在后台运行
我们当然也可以让进程在后台进行。先将code.c代码修改为每隔一秒打印一次:
在调用程序时在后面加上&即可让程序在后台运行, 也就是Windows上的最小化。但是此时还是在前台打印了,因为我们并没用和终端文件做脱离,如果脱离就看不到了。
T状态一般是进程做了非法但不致命的操作,被OS暂停了。
4.追踪暂停状态(t)
我们需要使用gdb来观察t状态,我们更改makefile,生成一个debug版本的可执行程序。
为了方便动态查询,我们编写一个简单的shell脚本,这里死循环每隔一秒打印关于code进程的信息。
while :; do ps ajx | head -1 && ps ajx | grep code | grep -v grep;sleep 1; done
此时运行代码,会在断点位置停下:
所以t(tracing stop追踪的暂停)状态的本质就是当前进程被暂停了。此时我们n执行一步程序。
可以看到由t状态变为S+状态。 当进程被追踪的时候,断点停下,进程状态就是t。
5.死亡状态(X)和僵尸状态(Z)
dead状态和Z(zombie)状态。
我们首先要知道,进程为什么要被创建出来?进程创建出来是为了完成用户任务的。但是进程结束,任务到底完成没有?这是通过进程执行的结果告知父进程/操作系统的。
5.1进程退出信息
我们这里来了解一个命令:$?
代表上一个进程退出时的退出信息,一般0代表程序正常退出,也就是完成任务;而其他就是任务就是出错的。
我们平时写的.c文件,在结尾都会有return,我们修改code.c代码,让其正常执行完并使用echo $?来查看退出结果(更加具体的细节会在环境变量和进程替换中讲解)。
关于X(dead)和Z(zombie)状态,我们先举一个例子:
有一个大爷,跑的很快,忽然倒下了。你在旁边经过,作为新时代的三好少年,你不会袖手旁观,于是你拨打了110,之后警察封锁了现场,法医进行了鉴定,之后对外宣布大爷是如何死亡的。这里我们就可以把大爷理解为进程,其状态如下:
对于Linux为什么有Z状态,因为我们要维持退出信息,方便父进程和操作系统来进行查询。
当一个进程退出的时候:
1.代码不会执行---首先可以立即释放进程对应的程序信息数据
2.进程退出,要有退出信息(进程的退出码)保存在tastk_struct(int exit_code)内部
3.管理结构task_struct必须被OS维护起来,方便用户未进行获取进程退出的信息。
所以一个进程在创建的时候第一步是先创建内核数据结构(struct_task),之后加载代码和结构。在销毁的时候先释放代码和结构,之后OS维护内核数据结构,最后根据情况释放。
接下来就用代码证明,我们先创建子进程,此时父子同时存在,之后让子进程退出,父进程什么都不做。
#include<stdio.h>
#include<unistd.h>int main()
{printf("父进程运行,pid: %d, ppid: %d\n\n",getpid(), getppid());pid_t id = fork();if (id == 0) {//子进程int cnt = 5;while(cnt){printf("我是子进程,我的pid: %d, ppid: %d, cnt: %d\n", getpid(), getppid(), cnt);sleep(2);cnt--;}}else {//父进程while(1){printf("我是父进程,我的pid: %d, ppid: %d\n", getpid(), getppid());sleep(1);}}return 0;
}
我们再次开启一个窗口,持续观察进程和进程状态,还是使用这个代码进行观察:
while :; do ps ajx | head -1 ; ps ajx | grep myprocess | grep -v grep; sleep 1; done
defunct : 失灵的,不再使用的,死的
当然我们还可以使用另外一种方法观察僵尸状态,我们修改myprocess.c代码,将子进程代码修改为死循环:
我们再次新开一个窗口,发送信号将子进程杀掉:
僵尸状态的进程,也称僵尸进程,维护自己的task_struct,方便父进程读取状态。也就是说,没人管它,它就是一直僵尸,task_struct也就一直占用内存资源,即使对应的代码和数据已经释放。此时存在的问题就是内存泄漏。
我们以前一般写的程序存在内存泄露我们一般发不现问题。是因为我们很快就把程序执行完了,但是在一个大项目中,不会很快就执行完程序,所以我们要避免内存泄漏。
最后,我们要回收这个进程,需要父进程读取子进程信息,子进程才会自动退出,此时task_struct也就会释放。
此时我们已经将子进程杀掉了,再次发送信号是无法杀掉的,因为你无法杀掉一个在概念上已经死掉的进程。
如何回收?我们后面再讲,不过这里先抛砖引玉一下,wait方法回收(在2号系统调用手册中)。
X状态是瞬时状态,我们捕捉不到,但是确实存在。
三、孤儿进程:
我们已经知道了僵尸进程,也就是父在子退;而还有另一种情况,就是父退子在。我们还用刚才的代码进行演示,这次我们将父进程杀死。
我们可以看到子进程成为了后端进程,所以先发送信号将其杀死。
这就奇怪了,在之前我们把子进程杀掉,其会变成僵尸状态;而我们把父进程杀掉他却没有变成僵尸状态,这是为什么?因为父进程的父进程是bash,当我们杀死父进程时,bash会自动回收。而子进程没有了父亲,PID为1的进程会将其领养。
接下来我们看看PID为1的进程时谁。执行top命令,我们可以先将其理解为任务资源管理器。
因为操作体统必须对所有的进程进行管理,当一个子进程没有父亲时,系统进程就会将其领养。
四、命令总结:
top命令:相当于任务资源管理器。
可执行程序 + &:该进程在后台运行。
echo $?:查看上次进程退出信息。
死循环查看进程信息脚本:
while :; do ps ajx | head -1 && ps ajx | grep code | grep -v grep;sleep 1; done
总结:
我们知道了进程的状态并且知道如何观察,但是这只是冰山一角,我们目前只是初窥门径,欲知后事如何,且听下回分解(记得追剧啊!)。
相关文章:

【Linux】进程状态(二)
目录 前言: 一、进程状态: 1.运行状态(时间片) 2.阻塞状态 3.阻塞挂起状态 二、Linux进程状态: 1.运行状态(R)和阻塞状态(S) 2.深度睡眠状态(D) 3.停止状态(T) 3.1使进程在后台运行 4.追踪暂停状态(t) 5.死亡状态(X)和僵尸状态…...

domain 网络安全 网络安全域
🍅 点击文末小卡片 ,免费获取网络安全全套资料,资料在手,涨薪更快 文章目录 1、域的概述 1.1、工作组与域1.2、域的特点1.3、域的组成1.4、域的部署概述1.5、活动目录1.6、组策略GPO 2、域的部署实验 2.1、建立局域网…...
链表和STL —— list 【复习笔记】
1. 链表 1.1 链表的定义和类型 和顺序表一样,链表也是一种线性表,线性表存储结构为链式存储就是链表 链式存储不仅要保存数据元素,还要保存数据元素间的关系,这两个部分信息形成了结点。结点有两个域:数据域&#x…...
Java Map实现类面试题
Java Map实现类面试题 HashMap Q1: HashMap的实现原理是什么? HashMap基于哈希表实现,使用数组链表红黑树(Java 8)的数据结构。 public class HashMapPrincipleExample {// 模拟HashMap的基本结构public class SimpleHashMap&…...
技术架构和工程架构区别
技术架构 技术架构是对某一技术问题解决方案的结构化描述,包括组件结构及其交互关系。它涵盖部署方案、存储方案、缓存方案、日志方案等多个方面,旨在通过组织人员和技术,以最低的成本满足需求和应对变化,保障软件的稳定高效运…...

简单介绍JVM
1.什么是JVM? JVM就是Java虚拟机【Java Virtual Machine】,简称JVM。主要部分包括类加载子系统,运行时数据区,执行引擎,本地方法库等,接下来我们一一介绍 2.类加载子系统 JVM中运行的就是我们日常写的JA…...

纷析云:赋能企业财务数字化转型的开源解决方案
在企业数字化转型的浪潮中,财务管理的高效与安全成为关键。纷析云凭借其开源、安全、灵活的财务软件解决方案,为企业提供了一条理想的转型路径。 一、开源的力量:自主、安全、高效 纷析云的核心优势在于其100%开源的财务软件源码。这意味着…...
DeepSeek开源周第二弹:DeepEP如何用RDMA+FP8让MoE模型飞起来?
一、引言:MoE模型的通信瓶颈与DeepEP的诞生 在混合专家(MoE)模型训练中,专家间的全对全(All-to-All)通信成为性能瓶颈。传统方案在跨节点传输时带宽利用率不足50%,延迟高达300μs以上。DeepSee…...

NLP学习记录十:多头注意力
一、单头注意力 单头注意力的大致流程如下: ① 查询编码向量、键编码向量和值编码向量分别经过自己的全连接层(Wq、Wk、Wv)后得到查询Q、键K和值V; ② 查询Q和键K经过注意力评分函数(如:缩放点积运算&am…...

【MySql】EXPLAIN执行计划全解析:15个字段深度解读与调优指南
文章目录 一、执行计划核心字段总览二、关键字段深度拆解1. type(访问类型)——查询性能的晴雨表典型场景分析: 2. key_len(索引使用长度)——索引利用率的检测仪计算示例: 3. Extra(附加信息&a…...

论文笔记(七十二)Reward Centering(五)
Reward Centering(五) 文章概括摘要附录B 理论细节C 实验细节D 相关方法的联系 文章概括 引用: article{naik2024reward,title{Reward Centering},author{Naik, Abhishek and Wan, Yi and Tomar, Manan and Sutton, Richard S},journal{arX…...
Linux内核自定义协议族开发指南:理解net_device_ops、proto_ops与net_proto_family
在Linux内核中开发自定义协议族需要深入理解网络协议栈的分层模型。net_device_ops、proto_ops和net_proto_family是三个关键结构体,分别作用于不同的层次。本文将详细解析它们的作用、交互关系及实现方法,并提供一个完整的开发框架。 一、核心结构体的作用与层级关系 struct…...

SOME/IP-SD -- 协议英文原文讲解6
前言 SOME/IP协议越来越多的用于汽车电子行业中,关于协议详细完全的中文资料却没有,所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块: 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 5.1.3.1 E…...
【数据处理】COCO 数据集掩码 Run-Length Encoding (RLE) 编码转二进制掩码
输入:结果.json 输出:mask.jpg json内容示例如下: {"labels":[ # class_id 1,2,3,...],"scores":[ # 置信度0.2,0.7,0.3,...],"bboxes":[[1244.0,161.0,1335.0,178.0],[1243.0,161.0,1336.0,178.0],[1242.0,1…...
Java中的缓存技术:Guava Cache vs Caffeine vs Redis
在Java中,缓存技术是提升应用性能的重要手段。常见的缓存技术包括Guava Cache、Caffeine和Redis。它们各有优缺点,适用于不同的场景。以下是对它们的详细对比: 1. Guava Cache 类型: 本地缓存 特点: 基于内存的缓存,适用于单机应…...

Day8 蓝桥杯acw讲解
首先先给大家看一道这个题, 我真的是太喜欢y总了,如果大家也是最近在准备蓝桥杯或者计算机相关的比赛,但是得加一个前提就是必须最好基础真的很好,要不然其实买了课,也没啥太大的用处,其实就可以以我本人举…...
《Operating System Concepts》阅读笔记:p147-p158
《Operating System Concepts》学习第 15 天,p147-p158 总结,总计 12 页。 一、技术总结 1.socket (1)定义 A socket is defined as an endpoint for communication(socket 是用于通信的端点,或者说socket 是通信端点的抽象表示。). A s…...

JSON Schema 入门指南:如何定义和验证 JSON 数据结构
文章目录 一、引言二、什么是 JSON Schema?三、JSON Schema 的基本结构3.1 基本关键字3.2 对象属性3.3 数组元素3.4 字符串约束3.5 数值约束 四、示例:定义一个简单的 JSON Schema五、使用 JSON Schema 进行验证六、实战效果6.1 如何使用 七、总结 一、引…...

java后端开发day20--面向对象进阶(一)--static继承
(以下内容全部来自上述课程) 1.static–静态–共享 static表示静态,是java中的一个修饰符,可以修饰成员方法,成员变量。 1.静态变量 被static修饰的成员变量,叫做静态变量。 特点: 被该类…...

FastJSON 默认行为:JSON.toJSONString 忽略 null 字段
完整的 FakeRegistrationController 代码,这让我可以全面分析后端逻辑,特别是为什么空的字段(如 compareDate)不返回给前端。我将详细分析代码的每个接口,尤其是与 list 请求和字段返回相关的部分,并解释原…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...