【Linux进行时】进程状态
进程状态:
❓假设我们在上课,在B站上上课,请问我们的B站是不是一直运行呢?💡不是的!
❓假设我们同时打开了B站和PDF阅读器时,是怎么运行的呢?
💡每一个进程在CPU跑一会,再从CPU拿下来放上另外一个上去,周而复始,这种叫做
分时操作系统
❓那就有一个问题,假设先用B站,为什么先将B站这个进程放上去,而不是PDF阅读器呢?
💡这就取决于进程状态!
思维导图:
1.进程的状态
1.1三种基本运行状态
- 运行状态
🔥R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里
。
❓一个进程只要把自己放到CPU上开始运行了,是不是一直要到执行完毕,才把自己放下来?
💡不是,每一个进程都有一个叫做:时间片的概念! 其时间大概是在10 ms左右。所以并不是一个进程一直在执行,而是这多个进程在一个时间段内所有代码都会被执行 —— 这就叫做【并发执行】
所以呢这就一定会存在大量的进程被CPU放上去、拿下来的动作 —— 这就叫做【进程切换】
- 并发and并行
🔥并行:指的是两个或者多个事件同一时刻发生(可以类比为一个公路,三台车不同道同向行驶)
🔥并发:指的是一段时间内有多个程序同时运行
- 就绪状态
🔥指的是进程已经处于准备好执行的状态,但是CPU没有空闲的,
- 阻塞状态和挂起状态
有两个概念:阻塞和挂起!
阻塞:进程因为等待某种条件就绪 ,而导致的一种不推进的状态——进程卡住了——阻塞一定在等待某种资源
就相当于进程太多了,卡着一个进程,在这个进程来看就是在等待CPU调度(某种资源)
🔥阻塞:进程等待某种资源就绪的过程
❓为什么阻塞呢?
💡进程要通过等待的方式,等具体的资源被别人是用使用完之后,再被自己使用。
❓什么是资源呢?💡资源=磁盘或者网卡显卡等各种外设(这是硬件,软件也有)
因为操作系统是通过先描述,后组织的方式来进行管理,假设用struct来代表这些外设用链表连接起来,
❓可以存在大量的进程吗?💡可以的❓要管理吗?💡先描述再组织
假设我们有一个进程task_struct要加载到cpu中,它在等待一个网卡资源
CPU说你不能在我上面跑了,所以task_struct就添加到这个队列的尾部等待网卡这个资源
也就是我们的task_struct在我们的列入到某种资源的队列当中,它就不会被CPU调度了吗,这不就是卡住了吗,不就是阻塞了吗!!!!
🔥pcb可以被维护在不同的队列中的!
阻塞:阻塞就是不被调度——一定是因为当前进程需要等待某种资源就绪——一定是进程task_struct结构体需要再某种被OS管理的资源下排队
挂起:
📚例子
假设task_struct是个下载任务,这里突然没网了,CPU说这个task_struct就不能跑了,task_struct就链接在网卡这个队列的中,这里就是阻塞了
操作系统通过自己的一套算法,把占有内存的,不被调度的进程的数据和代码交换到磁盘当中
磁盘那边放了一份交换后的代码和数据,这里的内存的代码和数据被释放,
在被再次调度前再把代码和数据换回来就可以了
🔥其中代码和数据由操作系统暂时将我们的从内存换到磁盘的过程中,此时这个进程就是挂起状态,全称叫做阻塞挂起状态
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上运行吗?💡不一定!
所有运行的进程只要在运行的队列中排队就可以了,所以CPU调度进程只要去我们的队列中去挑进程就可以了
❓进程是什么状态?💡一般也看这个进程在哪里排队
进程状态查看我们可以用ps
这里我们也能拿 ps 指令来看进程的状态,我们开小窗输入:
ps axj | head -1 && ps axj | grep process | grep -v grep
显然这里S是休眠状态
🔥首先需要声明一点,状态后面跟加号,表示是一个 **前台进程,**你只需要知道的是,能够在键盘上 Ctrl+c 暂停的都可以叫前台进程。
其实我们CPU的运行速度都很快,我们看到这里它一直在打印,其实是显示器(外设)一直在打印,CPU一瞬间就完成了,所以状态是S
我们将test.c中printf注释掉,再试一下
我们发现这里变成了R状态了
所以这个进程不访问任何资源,只等你 CPU,只要你被运行期间不访问外设,就不会被阻塞。
不访问外设,那么死也会在等待队列里,一直在等待队列中,这就让 process 达成 R状态!
🔥这里printf的本质就是向外设(网卡、显示器)打印消息,进程只要是R状态,并不直接代表进程正在运行,而代表该进程在运行队列中排队
🔥队列由操作系统自己维护
- 睡眠状态
S状态——休眠状态,可中断休眠,它一直在等待某种资源,其实就是阻塞状态
🔥我们一般把 状态叫作 浅度睡眠,也叫做 可中断睡眠。
- 顾名思义,当进程处于 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; }
将该进程运行起来我们可以看到其是出于S+
的状态,因为【shell】此时正在等待用户的输入,这个就对应到了我们上面所讲到的 阻塞状态
🔥不仅如此,像我们一直在使用的bash
,也可以算是一种【阻塞状态】,一直等待着我们去输入命令行,一旦有了的话它就进行读取
- 深度睡眠模式
这也是一种阻塞模式
"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
进程暂停与进程休眠(阻塞) 没有关系,只是单纯不想让这个进程跑了。
比如有些进程在执行任务时,用户想让这个进程暂停一下,这其实很好理解。
比如看视频,听音乐,下载,都会有暂停。当你点击暂停的时候下载对应的代码就不跑了,此时这个进程你就可以认为是暂停状态。
kill -19 进程pid 暂停该进程
kill -18 进程pid 解除暂停
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);}}
}
❓如果长时间处于僵尸状态,会有什么结果呢?
💡如果没有人收尸,该状态会一直维护,该进程的相关资源 (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一下,没有问题
这里的$@
和$^
$@代表冒号左侧的,红色的,目标文件
$^代表冒号右侧的,蓝色的,依赖文件
while :;do ps ajx | head -1&&ps ajx |grep myproc | grep -v grep;sleep 1;echo "----------";done
我们在旁边把程序运行起来
我们发现我们的父进程是5388 ppid 7666
子进程 5389 ppid5388
后面父进程中止了,只剩下子进程
子进程是5389 ppid变成了1
父进程这时候退出了那是不是应该处于僵尸状态呢?
这里我们为什么没有看到父进程处于僵尸状态呢?
我们在命令行中启动一个进程时,它的父进程是bash
父进程退出之后,它的父进程是bash(命令行解释器),所以这个父进程退出的时候,它的父亲帮他回收了
相当于是我死了,我爹bash帮我回收了
我们发现这个子进程的父进程死掉后,它给自己又找了个爹(1号进程),1好进程可以叫为操作系统
如果不领养会发生什么呢?
如果有一天这个子进程挂了,并且他没有父进程,他就会被操作系统遗忘,就一直处于一种占用操作系统内存空间的情况,也就是内存泄漏
相关文章:

【Linux进行时】进程状态
进程状态: ❓假设我们在上课,在B站上上课,请问我们的B站是不是一直运行呢?💡不是的! ❓假设我们同时打开了B站和PDF阅读器时,是怎么运行的呢? 💡每一个进程在CPU跑一会&a…...

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

友思特新闻|友思特与IDS深化战略合作伙伴关系
尊敬的客户和合作伙伴, 我们非常高兴地宣布,友思特已经与国际领先的机器视觉解决方案提供商 IDS 深化了我们的合作关系。 作为 IDS 的长期合作伙伴,友思特一直致力于为国内客户提供最先进的机器视觉技术和解决方案。 自从友思特与 IDS 合作…...

ARM Linux DIY(十三)Qt5 移植
前言 板子带有屏幕,那当然要设计一下 GUI,对 Qt5 比较熟悉,那就移植它吧。 移植 Qt5 buildroot 使能 Qt5,这里我们只开启核心功能 gui module --> widgets module 编译 $ make ODIY_V3S/ qt5base编译报错:找不…...

二,手机硬件参数介绍和校验算法
系列文章目录 第一章 安卓aosp源码编译环境搭建 第二章 手机硬件参数介绍和校验算法 第三章 修改安卓aosp代码更改硬件参数 第四章 编译定制rom并刷机实现硬改(一) 第五章 编译定制rom并刷机实现硬改(二) 第六章 不root不magisk不xposed lsposed frida原生修改定位 第七章 安卓…...

ubunutu20/18/22 编译android 5相关的问题汇总-千里马framework开源代码平板编译过程
hi,粉丝朋友们: 闲鱼50块钱淘到了一个开源平板,注意这个平板是有源码的,可以进行相关的编译修改。哈哈哈,马哥这边就体验了一下50块钱平板是否可以拿来做framework呢? 哈哈,说好就开干了&#x…...
tauri vue vite
准备 rust 根据 https://www.rust-lang.org/tools/install,安装 rust 执行 cargo --version 检查安装是否完成nodejs 安装 nodejstauri cargo install create-tauri-app --lockedcargo create-tauri-app 选择: ✔ Project name tauri-app ✔ Choose wh…...
名词解析与经验分享(前端)
目录 1.什么是sass产品 2.下面我想说说事件循环 3. cmd窗口的一些快捷键 4. 组件与插件的区别 5. vue项目嵌入app后调用app方法 6.点击编辑按钮直接回到顶部,输入框光标闪动聚焦 7.短轮询与长轮询 短轮询 长轮询 8.前端moment库 9.移动端-触底刷新实现核心…...
【前端】js下载url文件
不打开新窗口进行下载 function download(res) { var elemIF document.createElement("iframe"); elemIF.src res; elemIF.style.display "none"; document.body.appendChild(elemIF); } window.open(url, _blank); a标签 const ele …...

什么是 BSD 协议?
BSD开源协议是一个给于使用者很大自由的协议。可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有软件再发布。当你发布使用了BSD协议的代码,或者以BSD协议代码为基础做二次开发自己的产品时,需要满足三个条件&…...

【网络教程】揭秘Windows SSH服务端免密登录:告别繁琐,享受安全连接
文章目录 开启Windows下的SSH服务端图形界面安装手动下载安装Windows如何查看系统用户名Windows如何查看本机IP开启免密登录Window生成秘钥Linux下生成秘钥配置公钥视频讲解开启Windows下的SSH服务端 这篇文章演示的环境是Windows11Windows的SSH服务端默认情况下是没有安装的,…...
使用键盘控制Franka机械臂运动
功能说明 使用键盘按键,可以控制franka机械臂7个关节角,已在真机上验证。 代码 主要使用的是官方包内的 franka_example_controllers 1、修改 include下的 joint_position_example_controller.h, 改为如下: // Copyright (c) 2017 Frank…...
力扣第45天----第392题、第115题
# 力扣第45天----第392题、第115题 文章目录 一、第392题--判断子序列二、第115题--不同的子序列 一、第392题–判断子序列 挺简单的,思路跟以前的都差不多。 class Solution { public:bool isSubsequence(string s, string t) {vector<vector<int>&g…...

扔掉你的开发板,跟我玩Mcore-全志h616
本文转载自WhyCan Forum(哇酷开发者社区): https://whycan.com/t_10024.html 作者leefei 这是一个1.69寸触摸小电视。使用全志H616芯片,板上硬件有mpu6050陀螺仪,USB转ttl调试串口,一个USB接口,WIFI&蓝牙&#x…...
【Linux】网络篇:UDP、TCP 网络接口及使用
文章目录 socket 及 相关补充0. netstat - - 查询当前服务器上网络服务器1. 端口号(port)2. 网络字节序3. sockaddr 结构体 一、socket 常见 APIUDP0. IP 地址转化 函数1. socket 函数:创建 socket 文件描述符 (TCP/UDP, 客户端 服务器)2. b…...
卡尔曼滤波(Kalman Filter)原理浅析-数学理论推导-2
目录 前言数学理论推导卡尔曼增益超详细数学推导结语参考 前言 最近项目需求涉及到目标跟踪部分,准备从 DeepSORT 多目标跟踪算法入手。DeepSORT 中涉及的内容有点多,以前也就对其进行了简单的了解,但是真正去做发现总是存在这样或者那样的困…...

SQL 性能优化总结
文章目录 一、性能优化策略二、索引创建规则三、查询优化总结 一、性能优化策略 1. SQL 语句中 IN 包含的值不应过多 MySQL 将 IN中的常量全部存储在一个排好序的数组里面,但是如果数值较多,产生的消耗也是比较大的。所以对于连续的数值,能用…...
MYSQL事务隔离级别分析
MYSQL事务隔离级别分析 不可重复读和幻读的区别? 不可重复读和幻读的区别? 先理解几个概念 不可重复读 一个事务中,后续查询结果得到不同的数据,可被重复读隔离级别解决幻影 出现在查询结果集中但不出现在较早查询的结果集中的行幻…...

学习javaEE初阶的第一堂课
学习金字塔 java发展简史 Java最初诞生的时候是用来写前端的!! 199x年 199x年,互联网还处在比较早期的阶段,当时主流的编程语言是 C/C, 有个大佬要搞个"智能面包机",觉得用C来做太难了 于是就基于C搞了个简单点的语言,Java 就诞生了~~ 遗憾的是项目流产了,没做成…...

请问一下就是业务概念模型和业务逻辑模型有啥关系
请问一下就是业务概念模型和业务逻辑模型有啥关系? 业务概念模型和业务逻辑模型是业务建模的两个关键组成部分,两者密切相关但又有所不同。 1.业务概念模型:这是对业务术语、定义和关系的一种抽象表示。它是从业务专家那里获得的知识&#…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...

【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...