Linux第十三节 — 进程状态详解

news/2025/2/23 15:26:14

        只要一个进程的PCB还存在内存当中,哪怕此时该进程对应的代码和数据已经在磁盘当中,此时依然认为该进程仍然存在!

一、Linux进程的运行状态R

接下来我们看下面这个例子:

当我们执行这个程序的时候,我们认为该进程的状态应该是R,即一直运行,但是实际上却是S! 

如果我们此时将打印注释会变成什么呢?

 此时该进程则会一直变为运行态!

这是因为我们最初的代码包含printf函数,该函数需要访问我们对应的io设备,即显示器设备!此时设备不一致能直接进行打印,因此该进程很大概率需要等待!

R进程和R+进程的区别

  1. R (Running/Runnable)
    表示进程处于可执行状态,即正在CPU上运行或位于运行队列中等待调度。此时进程可能是后台进程,无法直接通过Ctrl+C等终端信号中断。

  2. R+ (Running & Foreground)
    在R的基础上,+符号表示进程属于前台进程组。这类进程可以接收终端的输入(如键盘信号),例如通过Ctrl+C终止或Ctrl+Z暂停。

一般默认的进程是在前台运行的,如果我们想要通过使用后台运行,可以在其增加&;

此时如果我们想要杀死后台程序,ctrl + c已经无效了,只能通过kill -9 来杀死;

二、Linux进程的睡眠状态S

Linux中具体的阻塞状态就是S状态!

上面两个代码对应的进程都需要从对应的IO设备获取相应的资源! 

大部分的情况下bash命令行的状态也是S!

因为要等待资源输入!(等待键盘输入对应的指令!)

S也被称为浅度睡眠 --- 随时可以对外界的动作做出具体的反应:可以唤醒或者kill

三、Linux进程的深度睡眠状态D(disk sleep)

不可中断睡眠状态(D - Uninterruptible Sleep)(deepseek)

  • 含义:进程因关键操作(如磁盘I/O)进入深度休眠,不响应任何信号 。
  • 特点
    • 常见于与硬件交互的短暂过程(如vfork后父进程等待子进程exit) 。
    • 无法通过kill终止,需等待操作完成或重启系统 。

        假如当前操作系统内有个进程 ,该进程需要往磁盘内写入1GB的数据;在磁盘拷贝数据期间,该进程没有其他事需要做,当此时操作系统内的空间特别紧张的时候,操作系统可能会杀掉该进程!最后磁盘写入数据后找不到进程或者直接导致数据丢失!

        因此出现了深度睡眠状态下的进程,此时该进程进入了不可杀的状态!

        即进程在等待磁盘写入的时候,此时的状态为D,也就是disk sleep;(也是阻塞状态的一种)

四、Linux进程的暂停状态T / t(stopped)

停止状态(T - Stopped)

  • 含义:进程被信号(如SIGSTOP - kill-19)暂停执行,可通过SIGCONT (kill-18)恢复 。
  • 场景
    • 用户主动暂停进程(如Ctrl+Z触发SIGTSTP) 。
    • 调试器(如gdb)断点调试时 。

假如说我们有当前如上所示的进程和对应的程序:

可以通过相关的信号进行暂停和继续:

  • kill -19可以暂停进程;
  • kill -18可以恢复暂停;

注意点:当我们暂停后再恢复过来,此时该进程会变为后台进程,需要杀掉只能通过kill -9;

问题:一个进程处于暂停状态和一个进程处于运行状态,这两个有区别吗?

其区别主要如下所示:

1. 触发原因

  • 停止状态(T/t)
    外部信号强制暂停,例如:

    • 用户发送SIGSTOP(暂停)或SIGTSTP(前台进程暂停,如Ctrl+Z)信号。
    • 调试器(如gdb)追踪时暂停进程(t状态) 。
  • 睡眠状态(S/D)
    进程主动等待资源或事件时进入,例如:

    • 等待用户输入(scanf)、磁盘I/O(S状态)。
    • 执行不可中断的硬件操作(如磁盘写入,D状态) 。

2. 唤醒方式

  • 停止状态(T/t)
    必须通过显式信号恢复(如SIGCONT),否则进程不会继续执行。

  • 睡眠状态(S/D)

    • S状态(可中断睡眠):当等待的事件完成(如I/O就绪)时自动恢复,或通过信号(如SIGKILL)中断 。
    • D状态(不可中断睡眠):仅当等待的硬件操作完成后自动恢复,不响应任何信号(包括SIGKILL) 。

暂停状态的应用场景

当我们通过gdb进行调试的时候,打完断点然后运行程序到断点处时,此时该进程的状态就为t(tracing stopped --- 追踪停止 --- 暂时可以将T和t当作是一种情况!)

五、Linux进程的死亡状态X(dead)

当我们杀掉一个进程的时候,该进程通常不会直接进入X状态,而是会经历一下的过程:

  • X状态(TASK_DEAD - EXIT_DEAD)是进程完全终止且资源已释放的最终状态,但极其短暂,几乎无法通过ps命令观察到 。
  • 被杀死(如kill -9)的进程通常先进入僵尸状态(Z),再短暂进入X状态后彻底消失

因此接下来我们引入僵尸进程Z;

六、Linux进程的僵尸状态Z(zombie)

一个进程挂掉了,此时最关心该进程的应该是其父进程!

因此,如果父进程此时并没有正确的回收子进程的资源,此时该子进程就会变为僵尸进程!

(危害方面。虽然单个僵尸进程影响不大,但大量存在会占用进程ID,导致系统无法创建新进程。PID资源有限,系统默认32768个,僵尸进程过多可能引发问题。)

假设我们当前有如下的程序:

接下来我们补充一点C语言的知识:

exit()函数的作用是什么?exit(0)是什么意思?

  •  exit()是C标准库中的一个函数,用于终止程序的执行,属于stdlib.h头文件;
  •  exit()函数的作用是什么?它会让程序立即终止,同时清理所有打开的文件和缓冲区,然后返回状态码给操作系统。状态码通常用来表示程序是正常结束还是出现了错误。比如,返回0通常表示成功,非零值表示不同的错误类型。
  • 需要注意的是,exit()和return语句的区别。在main函数中,return会调用exit(),所以效果类似,但如果在其他函数中,return只会返回,而exit()会直接结束整个程序。

        对于上面的代码,我们需要注意的是此时父进程并没有干扰子进程,和对其资源进行回收,我们仅仅是为了观察僵尸进程的状态!

情况一:我们直接运行该程序

我们可以发现当子进程运行到exit()后,其状态变为Z状态!(defunct指的是当前进程已经死亡,失效!)

进程一般退出的时候,如果父进程没有主动回收子进程的信息,子进程会一直让自己处于Z状态,此时进程的相关资源,尤其是task_struct结构体对象不能被释放掉!(会在内存中一直被占用!)

因为此时操作系统无法调用它,而它却一直占用着内存的资源,就会导致内存泄漏!

情况二:子进程运行完后将整个程序ctrl+c掉

此时ctrl+c之前:只有子进程变为僵尸进程,父进程没事!

之后,父子进程资源都被回收!

这里因为之后父子进程都被系统进行领养!

情况三:如果此时我们让父进程先退出

父进程运行5秒后直接退出,此时子进程继续运行!

运行的结果如下所示:

此时该子进程ppid直接变成了1!

 而PID对应编号为1的其实本身就是操作系统(systemd)!

因此此时我们可以得到结论:        

  • 父子进程,父进程先退出,子进程的父进程会被改为1号进程(操作系统);
  • 父进程为1号的进程1 --- 孤儿进程! --- 该进程被系统领养!

为什么被领养?

  • 因为孤儿进程未来也需要退出,也需要进行释放资源!

bash只能回收对应的子进程的资源,而对于子进程创建的其他进程没有权限!因此操作系统更合适!

        操作系统组织task_struct不仅仅是简单的使用一个双向链表连接起来,有可能这个节点不仅在链表当中,还存放在哈希,多叉树当中!

拓展:Linux中的task_struct之间是如何彼此访问数据的?

当前对于一个task_struct类型,我们只有一个strart的指针,如何获取上面的数据呢?

将0初始化为(tast_struct)类型,然后指向link,其实求得的link在task的偏移量!此时指针相减即可获取到上面的地址!(大致思路)

七、进程的优先级

什么是优先级?

优先级(对于资源的访问,谁先访问,谁后访问的问题)vs 权限;

为什么需要优先级?

因为资源是有限的,进程是多个的,注定了进程之间是竞争关系!

操作系统必须保证进程之间良性竞争,因此需要优先级!

如果一个进程长时间得不到推进,表现上就像是卡死了(例如window下某个程序卡死);

Vim进行批量化注释的操作:

  • ctrl+v进行命令模式(左下角弹出V-BLOCK);
  • 按JKL选中区域(不能按上下);
  • shift + i切换到插入模式;
  • 双斜杠//注释掉其中的一行;
  • 最后esc;

取消批量化注释的操作:

  • ctrl+v进行命令模式(左下角弹出V-BLOCK);
  • 按JKL选中区域(不能按上下);
  • 直接输入d;

如果我们想要查看进程的状态,可以通过ps -l / ps -al来查看:

命令显示范围输出格式典型用途
ps -l仅当前用户的进程长格式(详细)查看当前用户进程的详细状态
ps -al所有终端上的进程(含其他用户)长格式(详细)查看终端关联的所有进程的详情

接下来我们每隔一秒循环打印一段话,然后查看该进程的状态:

  • PRI这里指的就是进程的优先级!数字越小此时进程的优先级越高!
  • NI: 代表这个进程的nice值,可以通过更改nice的值来更改优先级;
  • UID指的是执行该进程的用户的ID(一般通过ls-ln即可查看到自己的用户ID);

优先级可以被调整!如果我们一直大量的更改nice值,是否可以控制我们的进程几乎一直在被调度?

理论上是可以的,但是我们不支持这样子做!Linux不想过多的用户参与优先级的调整,因此,我们只能在我们对应的范围内进行优先级调整,nice:[-20,19] ;

默认的优先级是80,因此进程的优先级范围为[60,99];

更改优先级

top 命令更改已存在进程的 nice
  • top
  • 进入top后按“r”–>输入进程PID–>输入nice

这里我们需要注意的是:旧的PRI值每次都是默认的80!不会继承上一次我们修改的值!

上面是Linux调用优先级的思想方法:

        当前CPU会根据运行队列调用进程,其中有两个指针数组:task_struct* running和task_struct* watting,数组的元素大小都为140个,这是因为进程优先级相关的前[0,99]是其他进程使用的,只有[100,139]供普通用户使用;

        其中running这个数组会指向我们需要运行的PCB,其中PRI值相同的进程会连接在一起,正好40个优先级范围对应40个数组的空闲位置;

        但是当该进程被运行的时候,又会有新的进程可能连接到后面需要被运行,因此操作系统也指定了一个waiting队列,,当running内的进程被运行的时候,新的进程插入到waiting当中,然后当running运行完了之后,再通过swap(&run,&wait),使得running一直为运行队列,waiting一直为等待队列!

如果一个运行队列运行完我们该怎么判断呢?

这里我们可以通过位图:char[5],正好是40个比特位;

如果该进程未被运行完设置为1,运行完则设置为0;

通过该思想即可控制进程之间的优先级! 


http://www.niftyadmin.cn/n/5863530.html

相关文章

BFS算法解决最短路径问题(典型算法思想)—— OJ例题算法解析思路

目录 一、1926. 迷宫中离入口最近的出口 - 力扣(LeetCode) 算法代码: 代码分析 各个部分的解释 注意事项 整体的含义 具体情况 使用 e[0] 和 e[1] 的优势 总结 示例代码中的用法 整体流程 示例 复杂度分析 总结 二、433. 最小基…

AWS S3深度解析:十大核心应用场景与高可用架构设计实践

摘要:作为全球领先的对象存储服务,Amazon S3凭借其高扩展性、持久性和安全性,已成为企业云原生架构的核心组件。本文将深入探讨S3的典型技术场景,并揭秘其背后的架构设计逻辑。 一、AWS S3核心技术特性解析 Amazon Simple Storag…

【系统架构设计师】操作系统的分类

目录 1. 说明2. 批处理操作系统3. 分时操作系统4. 实时操作系统5. 网络操作系统6. 分布式操作系统7. 微型计算机操作系统8.嵌入式操作系统9.例题9.1 例题1 1. 说明 1.通常,操作系统可分为批处理操作系统、分时操作系统、实时操作系统、网络操作系统、分布式操作系统…

ath9k(Atheros芯片)开源驱动之wifi连接

为什么会推荐这个wifi 驱动进行学习? ath9k(Atheros芯片):代码结构清晰,适合学习实践 为什么我只在开篇写了一个wifi连接的操作? 先让一个开源驱动在你的硬件上跑起来,再逐步修改&#xff0c…

深搜专题2:组合问题

描述 组合问题就是从n个元素中抽出r个元素(不分顺序且r < &#xff1d; n)&#xff0c; 我们可以简单地将n个元素理解为自然数1&#xff0c;2&#xff0c;…&#xff0c;n&#xff0c;从中任取r个数。 例如n &#xff1d; 5 &#xff0c;r &#xff1d; 3 &#xff0c;所…

Ubuntu 22.04安装K8S集群

以下是Ubuntu 22.04安装Kubernetes集群的步骤概要 一、设置主机名与hosts解析 # Master节点执行 sudo hostnamectl set-hostname "k8smaster" # Worker节点执行 sudo hostnamectl set-hostname "k8sworker1"# 所有节点的/etc/hosts中添加&#xff1a; ca…

基于Spring Boot的兴顺物流管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

[数据结构]双链表详解

目录 一、链表的分类 1. 单向或者双向 2. 带头或者不带头 3. 循环或者非循环 二、双向链表 1.双向链表内部定义 2.双向链表的初始化&#xff08;void LTPrint(LTNode* phead);&#xff09; 3.双向链表的销毁&#xff08;void LTDataDestroy(LTNode* phead);&#xff09…