当前位置: 首页 > news >正文

Linux—进程状态

目录

进程状态

理论:

执行状态:

阻塞状态:

挂起状态:

 进程切换:

实际:

睡眠状态 

可中断睡眠 S (sleeping)

不可中断睡眠 D (Disksleep)

运行状态 R (running)

停止状态

 停止状态 T (stopped)

跟踪停止状态 t (tracing stop)

 僵尸状态 Z (zombie)

 死亡状态X(dead)

 

孤儿状态(orphaned state)

总结 


进程状态

理论:

状态描述
新建状态进程刚被创建,尚未进入就绪队列。
就绪状态进程已准备好执行,等待 CPU 调度。
执行状态进程正在 CPU 上执行指令。
阻塞状态进程等待某事件(如 I/O 完成),无法执行。
挂起状态进程被从内存中移出,暂时停止执行。
终止状态进程执行完毕或异常终止,资源被回收。
状态转换路径转换说明
新建状态 → 就绪状态当进程被创建完成后,会被提交到就绪队列,进入就绪状态。
就绪状态 → 执行状态调度程序根据一定的调度算法,从就绪队列中选择一个进程,将 CPU 分配给它,使其进入执行状态。
执行状态 → 就绪状态如果进程的时间片用完,或者有更高优先级的进程进入就绪队列,当前进程会被剥夺 CPU,重新回到就绪状态。
执行状态 → 阻塞状态当进程在执行过程中需要等待某个事件(如 I/O 操作)时,它会主动放弃 CPU,进入阻塞状态。
阻塞状态 → 就绪状态当进程等待的事件发生时(如 I/O 操作完成),它会被唤醒,从阻塞状态回到就绪状态,等待再次被调度执行。
执行状态 → 终止状态当进程完成了所有的执行任务,或者因为异常情况被终止时,会进入终止状态,操作系统会回收其资源。
就绪状态 ↔ 挂起状态当内存充足时,挂起的就绪进程会被唤醒进入就绪状态;当内存不足时,部分就绪进程会被挂起以释放内存。
阻塞状态 ↔ 挂起状态当内存充足时,挂起的阻塞进程会被唤醒进入阻塞状态;当内存不足时,部分阻塞进程会被挂起以释放内存。
执行状态:

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行 

 

阻塞状态:

挂起状态:

 

 进程切换:

进程在切换,最重要的一件事情是:上下文数据的保护和恢复.


CPU 内的寄存器:
寄存器本身是硬件,具有数据的存储能力,CPU 的寄存器硬件只有一套!!
CPU 内部的数据,可以有多套,有几个进程,就有几套和该进程对应的上下文数据.
寄存器!= 寄存器的内容


CPU 内部的所有的寄存器中的临时数据,叫做进程的上下文

 

 我们经常写的函数代码

int add(int a, int b)
{int c = a + b;return c;
}int ret = add(10, 20)

结果就是通过寄存器返回的 

实际:

之前介绍过task_ struct内容

信息类别具体内容
标识符描述本进程的唯一标识符,用来区别其他进程。
状态任务状态,退出代码,退出信号等。
优先级相对于其他进程的优先级。
程序计数器程序中即将被执行的下一条指令的地址。
内存指针包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
上下文数据进程执行时处理器的寄存器中的数据。
I/O 状态信息包括显示的 I/O 请求,分配给进程的 I/O 设备和被进程使用的文件列表。
记账信息可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
其他信息进程间通信相关参数、资源限制设置、亲缘关系、安全上下文、调度策略与参数以及链接信息等内容

 进程状态:表示进程要么正在 CPU 上执行指令,要么已经准备好被 CPU 调度执行,处于就绪队列中等待获取 CPU 资源。

 linux-6.16内核源码

为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在Linux内核里,进程有时候也叫做任务)。 
下面的状态在kernel源代码里定义:

static const char * const task_state_array[] = { 
"R (running)", /* 0 */             #define TASK_RUNNING            0x00000000
"S (sleeping)", /* 1 */            #define TASK_INTERRUPTIBLE      0x00000001
"D (disk sleep)", /* 2 */          #define TASK_UNINTERRUPTIBLE    0x00000002
"T (stopped)", /* 4 */             #define __TASK_STOPPED          0x00000004
"t (tracing stop)", /* 8 */        #define __TASK_TRACED           0x00000008
"X (dead)", /* 16 */               #define EXIT_DEAD               0x00000010
"Z (zombie)", /* 32 */             #define EXIT_ZOMBIE             0x00000020
};
状态标识状态名称状态描述
R (running)运行状态并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里
S (sleeping)睡眠状态意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))
D (Disk sleep)磁盘休眠状态有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待 IO 的结束
T (stopped)停止状态可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行
t (tracing stop)跟踪停止状态进程被调试器(如 gdb)附加并暂停,用于跟踪调试
X (dead)死亡状态这个状态只是一个返回状态,你不会在任务列表里看到这个状态
Z (zombie)僵尸状态当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵尸进程。僵尸进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码

写个简单的代码,进行逐一理解:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{while(1){printf("I am a process!  pid:%d\n",getpid());sleep(1);}}

睡眠状态 

在 Linux 中,进程的睡眠状态(对应状态标识 S,即 "S(sleeping)"、 D,即 " D(Disksleep)"他们本质都是在等待进程资源就绪。

对比维度可中断睡眠(S 状态)不可中断睡眠(D 状态)
信号响应可被外部信号(如 SIGINT)中断不响应任何外部信号(包括 SIGKILL
适用场景等待用户输入、网络数据等非关键事件等待磁盘读写、硬件 I/O 等关键操作
唤醒条件事件完成  收到信号仅当 I/O 操作完成
数据安全性中断无风险强制中断可能导致数据丢失或硬件错误

可中断睡眠 (sleeping)

 写一个简单的shell脚本监控进程:

 while :; do ps axj|head -1 && ps axj|grep process|grep -v grep ;sleep 1;done
每隔 1 秒显示一次包含 "process" 名称的进程信息(含标题行),不显示grep 本身进程。

结果如图 

STAT总是S+ (睡眠状态),可是我们的程序一直在运行,为什么是睡眠状态呢?

  • S:表示进程处于睡眠状态(可中断睡眠),即进程正在等待某个事件(如 I/O 完成、信号等)。
  • +:表示该进程属于前台进程组,通常是当前终端中正在交互的进程。

可以用符号 & 用于将命令放到后台执行 

之前我们介绍过冯诺依曼和CPU运行速度:

显示器属于输出设备,是外设。他需要从内存中读取数据后刷新 。

CPU运行的速度极快,CPU 快速将数据写入到内存当中,并等待显示器就绪后刷新到显示器中,所以大部分时间都是在等待显示器资源就绪,我们就看见大部分时间进程都在等待。

 

进程处于休眠状态,但是可以被外部事件如Ctrl +C  打断时,叫做Linux 可中断睡眠

不可中断睡眠 (Disksleep)

因为电脑设备问题,不具体演示D状态。只做介绍:

不可中断睡眠也被称为不可中断休眠状态,是指进程正在等待某些特定的、关键的硬件资源操作完成,在此期间,进程不会响应除系统断电、硬件故障等极端情况外的任何外部信号(包括常用的SIGKILL 等强制终止信号),只有当等待的事件(通常是 I/O 操作)结束后,进程才会被唤醒,脱离该状态。

进入该状态的场景

  • 磁盘 I/O 操作:当进程需要从磁盘读取数据或者向磁盘写入数据时,可能会进入不可中断睡眠状态。比如一个数据库程序执行磁盘上数据文件的读写操作,在等待磁盘控制器完成数据传输的过程中,进程就会处于 D 状态。这是为了确保数据读写的原子性和完整性,避免在数据传输过程中因进程被中断而导致数据错误或丢失。
  • 其他硬件设备交互:除磁盘外,与其他外部硬件设备(如 USB 设备、打印机、网络设备等)进行数据交互时,若进程需要等待设备响应或操作完成,也可能进入不可中断睡眠。例如,当进程向打印机发送打印任务后,等待打印机确认接收并开始打印的过程中,可能处于不可中断睡眠状态。

 

解决办法:

1.重启--断电

2.等待进程自己醒来

 

运行状态 R (running)

在 Linux 中,进程的运行状态(对应状态标识 R,即 "R (running)")是指进程处于可被 CPU 调度执行的状态,具体包含两种情况: 

  1. 正在运行中:进程当前正在占用 CPU 资源,执行指令。
  2. 处于运行队列:进程已准备好执行,但暂时未获得 CPU 时间(因系统中存在多个就绪进程,需等待调度器分配 CPU 资源)。

当我们把之前的代码取消 printf 让 CPU 不与显示器打交道时:

我们可以看见进程一直处于运行状态。 

停止状态

在 Linux 中,进程的停止状态(对应状态标识 T,即 "T(stopped)"、 t,即 " t(tracing stop)"他们本质是进程暂停,等待进一步唤醒。

状态标识状态名称状态描述
T (stopped)停止状态可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行
t (tracing stop)跟踪停止状态进程被调试器(如 gdb)附加并暂停,用于跟踪调试

 

 停止状态(stopped)

我们先来了解两个信号

SIGCONT(18)

用于继续被暂停的进程,与 SIGSTOP 或 SIGTSTP 配合使用。

SIGSTOP(19)暂停进程,不能被进程捕获。

然后就可以暂停和开始了:

跟踪停止状态 t (tracing stop)

跟踪停止状态:进程被调试器(如 gdb)附加并暂停,用于跟踪调试

我就用之前gdb写的代码来测试: 

 

 僵尸状态 (zombie)

僵尸状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用 wait () 系统调用)没有读取到子进程退出的返回代码时,就会产生僵尸进程。

 

僵尸进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。

 

所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程就会进入僵尸状态(Z 状态)。

之前我们说 进程=内核数据结构task_struct +代码 +数据

部分代码和数据可以释放,但是task_struct 要保留给父进程读取退出状态,如果父进程一直不读取,就会造成内存泄漏。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t pid=fork();if(pid==0){int cnt=5;while(cnt){printf("I am Child pid:%d cnt=%d\n",getpid(),cnt);sleep(1);cnt--;}}else{while(1){printf("I am parent pid=%d \n",getpid());sleep(1);}}return 0;}

 死亡状态X(dead)

X(死亡状态)是进程生命周期的终点,代表进程彻底执行完毕且资源正被操作系统释放,因持续时间极短,无法在任务列表中观测到,因此不做演示。

 

孤儿状态(orphaned state)

当父进程先于子进程终止时,子进程就会进入孤儿状态(orphaned state),随后被系统的初始化进程(如 init 或 systemd)接管,由其负责最终的资源回收。

总结 

http://www.dtcms.com/a/312225.html

相关文章:

  • 深入 Go 底层原理(九):context 包的设计哲学与实现
  • 智能手表:电源检查
  • Java多线程详解(2)
  • 一、灵巧手捉取几何原理——空间五指平衡捉取
  • GraphRag安装过程中的报错:系统找不到指定的文件(Could not install packages due to an OSError)
  • AI赋能测试:技术变革与应用展望
  • C++const成员
  • [网安工具] Web 漏洞扫描工具 —— AWVS · 使用手册
  • 机器学习【五】decision_making tree
  • Linux重定向和缓冲区
  • Piriority_queue
  • 三、摩擦刚体——捉取质量函数
  • ARP协议是什么?ARP欺骗是如何实现的?我们该如何预防ARP欺骗?
  • 前端与后端部署大冒险:Java、Go、C++三剑客
  • Codeforces Round 1039 (Div. 2) A-C
  • nodejs读写文件
  • 数据类型Symbol
  • 裸露土堆识别准确率↑32%:陌讯多特征融合算法实战解析
  • 数据结构基础
  • Minimizing Coins(Dynamic Programming)
  • 【智能体cooragent】创建 workflow 时 候选 Agent 和 Tool 获取来源详细分析
  • Python从入门到精通——第五章 列表与元组
  • 机器人学中路径规划(Path Planning)和轨迹生成(Trajectory Generation)关系
  • 海康皓视通 对接测试和比较
  • 【学习笔记】MySQL技术内幕InnoDB存储引擎——第8章 备份与恢复
  • 自进化智能体综述:通往人工超级智能之路
  • 安卓自动点击器:设置点击周期 / 滑动,抢票、游戏刷日常秒会
  • UNet改进(28):KD Attention增强UNet的知识蒸馏方法详解
  • 适 配 器 模 式
  • Anthropic最新研究Persona vector人格向量