进程状态:Linux的幕后指挥管理,穿越操作系统进程的静与动

文章目录

引言:进程的生命与状态:动与静的交响曲

每一个进程都拥有自己的生命轨迹,它们在CPU的调度下,按照某种规律从一个状态转变到另一个状态。这些状态是进程在操作系统内存空间中的各种"存在形式",是它们生命周期的不同表现,承载着操作系统对每个进程的管理与调度。

在Linux这个庞大而复杂的宇宙中,每个进程如同宇宙中的星辰,承载着数据流动与信息处理的重任。而它们的生命周期,却不仅仅是简单的"开始"与"结束"。在这无尽的天际,进程的状态不断变化,如同风中的细沙,或稳静、或急躁、或急促、或安逸。今天,我们将一同探索,深入理解Linux操作系统中进程状态的神秘面纱。

一、操作系统中的进程状态概述

操作系统中的进程状态是进程在生命周期中可能处于的不同状态。这些状态帮助操作系统识别进程的运行情况,并在不同状态间进行合理的资源分配

操作系统中的经典进程状态包括就绪运行阻塞终止

1.1 经典的进程状态模型

典型的操作系统中,进程状态可以分为以下几种:

在这种经典模型中,进程会在不同状态之间流转。具体来说:

就绪 -> 运行:CPU调度器分配CPU给就绪状态的进程。

运行 -> 阻塞:进程等待I/O或其他资源时进入阻塞状态。

阻塞 -> 就绪:等待的条件满足后,进程重新进入就绪队列,等待CPU调度。

运行 -> 终止:进程执行完毕或异常终止,进入终止状态。

1.2 进程状态转换图

该图展示了一个经典进程状态的转换流程。箭头表示进程状态转换的可能路径。

二、Linux操作系统中的进程状态

Linux操作系统在经典的进程状态基础上进行了一系列扩展,允许内核更细粒度地控制进程,尤其是当系统资源紧张或多任务并发性很高时。Linux内核中的进程状态可以使用ps命令或读取/proc文件系统来查看进程的状态信息。

2.1 Linux进程状态的分类

在进程的task_struct结构体中,state字段用来表示进程的当前状态。根据内核中的定义,不同状态的进程会被挂载在不同的等待队列上,以实现细粒度的调度与控制。

而在我们 Linux 中,新建就绪运行都可以看作 运行 R 这一个状态,所以比较清晰

2.2 各状态的详细解释

  • TASK_RUNNING:进程正在运行或准备运行。它可以被调度器分配到CPU执行。TASK_RUNNING的进程始终是就绪队列的一部分。

  • TASK_INTERRUPTIBLE:进程处于可中断等待状态,等待某一条件满足。进程在此状态下可以被信号唤醒。(关于信号的知识我们在后面会讲)

  • TASK_UNINTERRUPTIBLE:进程处于不可中断的等待状态。这通常用于等待特定资源(例如设备I/O操作完成)。进程在此状态下不会被信号打断,即便外部发送信号也不会响应。

  • TASK_STOPPED:进程被暂停,通常是由于接收到SIGSTOP信号或调试器干预,等待继续或恢复信号。

  • TASK_TRACED:进程被调试工具(如gdb)跟踪和控制。此状态下的进程会暂停,直到调试器进一步控制。

  • EXIT_DEAD:进程终止后进入清理阶段,等待系统回收资源

  • EXIT_ZOMBIE:进程已结束,系统未回收其资源。僵尸进程会保留在系统中,直到其父进程调用wait()系统调用收集它的退出状态。

  • TASK_DEAD:表示进程已彻底结束,系统已回收其所有资源。

2.3 Linux进程状态表

2.4 使用ps查看进程状态

在Linux系统中,可以通过ps命令查看进程的状态:

bash 复制代码
ps -aux

ps命令会显示每个进程的详细信息,其中状态列标记着每个进程的状态。状态的含义如下:

  • R : 运行或就绪状态
  • S:可终止等待
  • D: 不可终止等待
  • Z: 僵尸进程,等待回收
  • X:终止死亡进程
  • T: 停止状态

我们也可以通过ps命令查看某个指定的进程的信息:

bash 复制代码
ps axj | grep 进程名字

三、进程状态具体分析

🖋️运行 R

首先来看看第一种状态 R

以我们以往的认知来说,一个程序在运行就表示该 进程 处于 运行 状态,那么事实真的如此吗?

先来看看下面这段代码:

bash 复制代码
#include<iostream>
using namespace std;

#include<unistd.h>
#include<sys/types.h>

int main()
{
  while(1)
  {
    cout << "I'm a process, my PID is:" << getpid() << endl;
    sleep(1);
  }
  return 0;
}

当前makefile文件为:

bash 复制代码
myProcess:test.cpp
	g++ -o myProcess test.cpp

.PHONY:catPI
catPI:
	ps ajx | head -1 && ps ajx | grep myProcess | grep -v grep 

.PHONY:clean
clean:
	rm -r myProcess

通过 make catPI 指令调用 Makefile 中提前设定好的指令,查看当前进程信息

可以看到当前的进程状态为 睡眠 S+
注: + 表示当前进程在前台运行中

进程 难道没有运行吗?

运行了,但我们 很难捕捉到 对于 CPU 来说,将这么简单的一句话输出到屏幕上是一件很小的事,可能几毫秒就完成了 而其他大多数时间,进程

都在外设等待队列中 排队 当我们将打印语句和睡眠语句屏蔽后,进程 不用在等待队列中 排队, CPU 就一直在处理死循环,此时可以观察到 运行R 状态

🖋️睡眠 S

睡眠 S 的本质就是 进程阻塞表示此时进程因等待某种资源而暂停运行

睡眠 S 又称为可中断休眠,当 进程 等待时间过长时,我们可以手动将其关闭,应用卡死后强制关闭也是这个道理

还有一种方式终止进程:kill

  • kill -9 PID 终止进程,当进程在后台运行时(状态不加 +),我们是无法通过 ctrl+c 终止的,但kill指令可以终止

🖋️休眠 D

还存在一种特殊睡眠状态 休眠 D休眠 又被称为不可中断休眠,顾名思义,休眠 D 状态下的 进程 是无法终止的,kill 指令和 OS都无能为力,只能默默等待 进程阻塞 结束,拿到资源了,进程 才会停止 休眠 D 状态

终止 休眠 D 进程的一个方法就是切断电源,此时进程是结束了,但整个系统也结束了

🖋️暂停 T

我们还可以使 进程 进入 暂停 T 状态

  • kill -19 PID 暂停进程
  • kill -18 PID 恢复进程

在输入暂停指令后,进程进进入暂停状态


我们可以通过 kill -18 PID 使 进程 恢复运行,恢复后的 进程 在后台运行

可以看到,恢复后进程继续执行,并且状态由T变为S

注意: 进程 在后台运行时,是无法通过 ctrl+c·指令终止的,只能通过 kill -9 PID 终止

在 gdb 中调试代码时,打断点实际上就是 使 进程 在指定行暂停运行,此时 进程 处于 追踪暂停状态 t


🖋️死亡 X

当进程被终止后,就处于 死亡 X 状态

死亡状态是无法在任务列表中观察到的,死亡 X 状态只是一个返回状态

🖋️僵尸 Z

与死亡状态相对应的还有一个 僵尸 Z 状态

  • 通俗来说,僵尸状态 是给 父进程 准备的
  • 当 子进程 被终止后,会先维持一个 僵尸 状态,方便 父进程 来读取到 子进程 的- 退出结果,然后再将 子进程 回收
  • 单纯的在 bash 环境下终止 子进程,是观察不到 僵尸状态 的,因为 bash 会执行回收机制,将 僵尸 回收
  • 我们可以利用 fork() 函数自己创建 父子进程 关系,观察到这一现象

代码示例如下:

cpp 复制代码
#include<iostream>
using namespace std;

#include<unistd.h>
#include<sys/types.h>

int main()
{
  pid_t ret = fork();
  if(ret == 0)
  {
    while(1)
    {
      cout << "I'm son process, my PID: " << getpid() << " PPID: " << getppid() << endl;
      sleep(1);
    }
  }
  else if(ret > 0)
  {
    while(1)
    {
      cout << "I'm father process, my PID: " << getpid() << " PPID: " << getppid() << endl;
      sleep(1);
    }
  }
  else
  {
    while(1)
    {
      cout << "Make son process fail!" << endl;
      sleep(1);
    }
  }

  return 0;
}

此时进程开始执行

此时父子进程都处于常规睡眠状态

此时输入指令 kill -9 PIDkill -9 1007716终止 子进程

再次查看进程状态:

僵尸进程如果不被回收,会导致内存泄漏问题和标识符占用问题

📖孤儿进程

孤儿进程是一种特殊的进程状态

  • 通过程序创建 父子进程
  • 通过指令终止 父进程,此时 子进程 会被OS领养
  • 子进程 的 父进程 变为 1号进程
  • 子进程 就变成了一个 孤儿进程

同样执行上述代码,起初都正常运行

现在我们消灭父进程,观察其执行结果和运行状态

可以看到子进程被1号进程领养

假设 子进程 不被 1号进程 领养

  • 子进程 退出时就会无人回收,成为一只游离的僵尸
  • 僵尸进程 有 内存泄漏 的风险
  • 因此 子进程 会被OS领养

总结:进程状态的舞蹈

Linux操作系统中的进程状态,不仅仅是抽象的计算机术语,它们是系统中每个进程生命周期的具体体现。正如一场精彩的舞蹈,每个进程都有自己的节奏和步伐,它们或快速跃动,或缓慢舞动,或瞬间消失,而每个转变都与操作系统对资源的调度和管理息息相关。

通过理解进程状态与状态转变的过程,我们能够更好地把握Linux系统的脉搏,掌握进程管理与调度的奥秘。这不仅是操作系统中的技术问题,更是数字世界中的一场优雅的舞蹈。

本篇关于进程状态的介绍就暂告段落啦,希望能对大家的学习产生帮助,欢迎各位佬前来支持斧正!!!

相关推荐
UpUpUp……10 分钟前
Linux--JsonCpp
linux·运维·服务器·c++·笔记·json
Willis_m27 分钟前
Linux 服务器用 SSH 拉取多个 Git 工程
linux·服务器·git·ssh
紫金修道34 分钟前
【Linux】在Arm服务器源码编译onnxruntime-gpu的whl
linux·服务器·arm开发
xq5148632 小时前
Linux系统下安装mongodb
linux·mongodb
柒七爱吃麻辣烫2 小时前
在Linux中安装JDK并且搭建Java环境
java·linux·开发语言
孤寂大仙v3 小时前
【Linux笔记】——进程信号的产生
linux·服务器·笔记
深海蜗牛3 小时前
Jenkins linux安装
linux·jenkins
愚戏师3 小时前
Linux复习笔记(三) 网络服务配置(web)
linux·运维·笔记
JANYI20184 小时前
嵌入式MCU和Linux开发哪个好?
linux·单片机·嵌入式硬件
熊大如如4 小时前
Java NIO 文件处理接口
java·linux·nio