进程状态 —— Linux内核(Kernel)

发布于:2025-09-01 ⋅ 阅读:(18) ⋅ 点赞:(0)

在这里插入图片描述


在这里插入图片描述


🎁个人主页:工藤新一¹

🔍系列专栏:C++面向对象(类和对象篇)

🌟心中的天空之城,终会照亮我前方的路

🎉欢迎大家点赞👍评论📝收藏⭐文章


进程状态

前提回顾:进程概念


进程状态指的是一个进程在其生命周期中所处的阶段

​ 对于进程来讲,进程状态用于决定,当前进程要被调渡?运行?正在休眠?正在进行等待?在系统层面,当前进程状态决定 OS 应该如何处理这个进程

进程状态本质:task_struct 内部的一个整形变量(整数),后续 OS 会根据这个 “整数”(标志位) 进行判断

在这里插入图片描述


一、Linux内核源代码

  • 运行 && 阻塞 && 挂起

在这里插入图片描述


1.1运行状态

​ 一个进程在 CPU 上运行时,其就是运行状态。在当代的计算机中,只要一个进程在调渡队列当中,我们就称该进程为运行状态 [并不是一个进程持有 CPU,才能叫做运行]

运行:进程在调渡队列中,进程的状态都是 running!
处于 running 状态的进程,要么正在被 CPU运行,要么已经完全准备完毕,随时等待被调渡

在这里插入图片描述


OS

运行队列(Run Queue):

在这里插入图片描述



1.2阻塞状态

​ 在学习变成语言中,我们会遭遇的阻塞经历:cin/scanf。**传统意义上:**我们自己写的 C++ 代码,编译起来就是一个进程,当代码从上至下执行至 cin/scanf 我们的程序就停下来了[等待用户输入],输入数据后,当程序拿到了这份数据后,程序就会继续向后运行了

现代计算机理解中:当我们 cin/scanf 时,其实程序并不是在等待用户输入,而是等待键盘硬件就绪。在用户未按下键盘时,我们称之为键盘硬件未就绪,此时 cin/scanf 也就无法读取数据。因此,阻塞的意义:等待某种设备/资源就绪。在此期间,设备/资源未就绪,那么进程就不会被调渡


OS

设备队列(struct_device device):*

在这里插入图片描述


运行:进程在调渡队列中你进程的状态都是 running

阻塞:等待某种设备或资源就绪 [OS 会管理系统中的各种硬件资源:“先描述,在组织!”]


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


结论:进程状态的变化,表现之一是,要在不同的队列中进行流动。本质是数据结构的增删查改!


1.3进程的挂起

1、阻塞挂起状态

在这里插入图片描述


问题:如果在阻塞挂起状态,键盘突然就绪了呢?
因为OS是设备(软硬件设备)的管理者,所以OS会将对应进程,曾经换入到磁盘中的历史上的数据和代码,重新加载到内存,重新构建指针映射,最后将这些代码和数据换入内存后,形成完整进程,最后将进程放入运行队列中 —— 这一过程,我们称之为 swap 对应的 “换入和唤出” 操作

其中,
进程所对应的代码数据被放进交换分区:进程阻塞挂起
当进程换入时,将阻塞挂起进程重新改为运行状态,该进程就可以直接继续被调渡

挂起:将对应进程的代码和数据挂到外设(磁盘)上

换句话说,OS是一个非常智能的软件,当内存资源不足时,OS需要在整个系统层面上对内存资源进行 “辗转腾挪”


2、运行挂起状态

OS内存资源,“相当” 吃紧,阻塞的进程资源全部挂起到外设上,内存仍然短缺,那么 OS只能打 运行队列 中进程的主意了。OS 甚至会将处于运行队列末端的进程,交换给 swap 中,当真正真正调渡该进程时,再把对应进程换入


挂起的本质:暂时中止进程/线程的执行,将进程数据换入/唤出到磁盘的 swap 分区中,并保存其当前状态[PCB],以便后续恢复

在这里插入图片描述


1.4理解Linux内核链表话题

如何遍历整个进程?


数据结构中的双链表:

在这里插入图片描述


Linux 内核[kernel]中的双链表结构:

在这里插入图片描述


task_struct 内部嵌套链表:

在这里插入图片描述


在这里插入图片描述


链表差异:

在这里插入图片描述


C 语言地址转化(宏 - offset):获取结构体中所有字段地址

在这里插入图片描述


在这里插入图片描述


**最终结论:**以 offset 遍历链表,即可以访问进程(PCB)中的所有结构体中的所有字段

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

**结论:我们所对应的PCB在kernel中只存在一份,但同一个PCB可以同时映射于多种数据结构中。 **如此独特的性能归结于 kernel 中独有的双链表结构[list_head],以 list_head 为中心设计独有的算法

kernel 中的数据结构不是单一结构,如进程[PCB]可能即属于运行队列,又属于全局链表;还可能即被放在运行队列中,又被放在等待队列中,这意味着:Linux中很多数据结构是网状的!


二、Linux的进程状态

在这里插入图片描述


在这里插入图片描述


2.1运行状态(R/R+)

“R - 0”

在这里插入图片描述


在这里插入图片描述


2.2阻塞状态(S)

“S - 1”

  • Linux角度 - 休眠状态
  • 操作系统角度 - 阻塞状态(等待某种资源准备就绪:等待键盘输入)

在《操作系统》理论中,阻塞状态被称为:阻塞。但在 Linux 内核中阻塞状态我们称之为 S

我们在用户层直观的看到一个程序卡住不动了,说到底就是进程不被调渡了(有可能是在等待硬件设备的输入),因此这就是阻塞状态

在这里插入图片描述


在操作系统理论课程中,我们无从得知阻塞的标志位具体是什么的(0?1?…),但具体操作系统可以告诉我们 Linux的阻塞状态是 ”S - 1“


2.3暂停状态(t && T)

t - 追踪状态

在先前我们的操作系统理论中并没有暂停状态;但在 Linux 当中是存在暂停状态的

在这里插入图片描述


在这里插入图片描述


T - 暂停状态

  • T (Stopped):进程的执行被暂停,通常是由于收到了一个信号(例如 SIGSTOP 信号或调试器的断点信号)
  • 可以被重新唤醒,继续运行(例如通过发送 SIGCONT 信号)

在这里插入图片描述


什么是暂停状态?暂停状态又是什么呢?暂停状态又如何与 kernel状态对应起来呢?

一般暂停状态[T]与阻塞状态[S]不一样(**进程阻塞S:**一个进程在等待某种资源;**进程暂停T:**不具备某种条件或进程做了非法操作,那么操作系统就将对应的进程暂停了,这属于Linux特有的一种状态)

  • 暂停状态(t && T):止损;操作系统怀疑进程有问题,将进程暂停[t - 断点调试;T - Ctrl + Z]交给用户,让用户裁决是否继续进程

2.4 D状态(深度睡眠、不可中断睡眠)

进程在等待某个事件(如等待输入输出完成、等待信号量、等待网络数据等)而暂停运行。睡眠态分为两种:

  • 可中断睡眠态
    • S (Interruptible Sleep):进程在等待一个事件的完成。在这种状态下,进程可以被信号唤醒(例如用户按了 Ctrl+C)或中断
    • 常见例子:等待用户键盘输入、等待套接字连接
  • 不可中断睡眠态
    • D (Uninterruptible Sleep):进程也在等待事件(通常是I/O操作),但不能被信号唤醒或中断。这是为了保护某些关键的进程,确保它们在完成特定任务前不会被打断
    • 常见例子:等待磁盘I/O操作。如果系统上有大量 D 状态的进程,通常意味着硬件(如磁盘)可能遇到了问题

休眠状态S,我们称之为可 中断睡眠(也叫浅度睡眠)[Linux中具体个性化的概念]。可终端休眠:如果一个进程处于 S状态,我们直接杀掉这个进程,这个进程会 响应 我们杀掉它的动作[给出反应]

在这里插入图片描述


”D“ 状态的进程不可被 kill掉!那什么时候 ”D“状态就结束了呢?:一旦进程处于 ”D“状态,那就只能等待该进程自己醒来,OS 无权杀掉它!;或者重启,甚至只能断电!

在这里插入图片描述


2.5死亡状态(结束状态)

  • X (Dead):进程已经完全死亡并被回收。这个状态只是一个瞬间状态,用户无法在 pstop 等工具中看到这个状态的进程。(注意区分 僵尸状态死亡状态 的时间阶段:(先)僵尸状态—>(再)死亡状态

总结

状态 符号 含义 是否消耗资源
运行/可运行 R 正在或即将使用CPU
可中断睡眠 S 等待事件,可被信号唤醒 否(等待中)
不可中断睡眠 D 等待I/O,不可被信号唤醒 否(等待中)
僵尸 Z 已终止,等待父进程回收 否(但占用PID)
停止 T 被信号暂停执行

在这里插入图片描述
🌟 各位看官好我是工藤新一¹呀~

🌈 愿各位心中所想,终有所致!


网站公告

今日签到

点亮在社区的每一天
去签到