进程状态 —— Linux内核(Kernel)
🎁个人主页:工藤新一¹
🔍系列专栏:C++面向对象(类和对象篇)
🌟心中的天空之城,终会照亮我前方的路
🎉欢迎大家点赞👍评论📝收藏⭐文章
文章目录
- 进程状态
- 一、Linux内核源代码
- 1.1运行状态
- 1.2阻塞状态
- 1.3进程的挂起
- 1.4理解Linux内核链表话题
- 二、Linux的进程状态
- 2.1运行状态(R/R+)
- 2.2阻塞状态(S)
- 2.3暂停状态(t && T)
- 2.4 D状态(深度睡眠、不可中断睡眠)
- 2.5死亡状态(结束状态)
- 总结
进程状态
前提回顾:进程概念
进程状态指的是一个进程在其生命周期中所处的阶段
对于进程来讲,进程状态用于决定,当前进程要被调渡?运行?正在休眠?正在进行等待?在系统层面,当前进程状态决定 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):进程已经完全死亡并被回收。这个状态只是一个瞬间状态,用户无法在
ps
或top
等工具中看到这个状态的进程。(注意区分 僵尸状态 与 死亡状态 的时间阶段:(先)僵尸状态—>(再)死亡状态)
总结
状态 | 符号 | 含义 | 是否消耗资源 |
---|---|---|---|
运行/可运行 | R | 正在或即将使用CPU | 是 |
可中断睡眠 | S | 等待事件,可被信号唤醒 | 否(等待中) |
不可中断睡眠 | D | 等待I/O,不可被信号唤醒 | 否(等待中) |
僵尸 | Z | 已终止,等待父进程回收 | 否(但占用PID) |
停止 | T | 被信号暂停执行 | 否 |
🌟 各位看官好,我是工藤新一¹呀~
🌈 愿各位心中所想,终有所致!