Linux 进程与进程状态・三层级深度解析
目录一、进程概念Process第一层・定义级第二层・原理级第三层・对比级二、进程状态详解0. 状态总览1. 运行态Running / TASK_RUNNING第一层・定义级第二层・原理级第三层・对比级2. 就绪态Ready第一层・定义级第二层・原理级第三层・对比级3. 阻塞态Blocked / Sleeping第一层・定义级第二层・原理级第三层・对比级Demo阻塞态观察4. 僵尸态Zombie / EXIT_ZOMBIE第一层・定义级第二层・原理级第三层・对比级Demo僵尸进程制造与观察5. 孤儿态Orphan第一层・定义级第二层・原理级第三层・对比级面试三层级方法论​• 第一层定义级能说出是什么、有什么用 —— 及格线​• 第二层原理级能讲清楚底层怎么实现、为什么这么设计 —— 加分项​• 第三层对比级能横向对比同类方案、讲 trade-off、结合项目说一、进程概念Process第一层・定义级是什么进程是程序的一次运行实例是操作系统进行资源分配和调度的基本单位。程序 存放在磁盘上的二进制文件静态的、死的进程 程序被加载到内存中运行后的实体动态的、活的有什么用资源隔离每个进程有独立的地址空间一个进程崩了不影响其他进程并发执行OS 通过切换进程让多个程序 同时 运行权限管理每个进程有 uid/gid系统据此控制资源访问权限第二层・原理级底层怎么实现Linux 内核用一个叫 task_struct进程描述符的巨型结构体来描述一个进程存在内核栈底部 / 单独的 slab 缓存中。核心字段struct task_struct { volatile long state; // 进程状态 void *stack; // 进程内核栈指针 pid_t pid; // 进程ID pid_t tgid; // 线程组ID struct mm_struct *mm; // 用户态地址空间 struct files_struct *files;// 打开的文件表 struct signal_struct *signal; // 信号处理 struct sched_entity se; // 调度实体CFS调度用 struct task_struct *parent;// 父进程指针 // ... 几百个字段 };为什么这么设计独立地址空间mm_struct通过页表实现虚拟内存隔离安全性高代价是进程切换要刷 TLB开销大task_struct 放内核态用户态无法直接修改保证内核数据结构安全父子关系树形结构所有进程以 init 进程为根形成进程树便于资源回收和信号传递第三层・对比级维度进程线程协程资源粒度资源分配基本单位独立地址空间调度基本单位共享进程地址空间用户态调度共享线程栈空间切换开销大页表、TLB、文件表全换小只换寄存器和栈极小用户态完成无内核陷入通信方式IPC管道、消息队列、共享内存共享变量 锁直接函数调用式协作崩溃影响单个进程崩溃不影响其他一个线程崩溃 → 整个进程挂同线程内协程一起挂适用场景需要强隔离的独立程序CPU 密集型并发、IO 多路复用高并发 IO、轻量任务调度二、进程状态详解0. 状态总览Linux 内核中state字段的核心宏定义#define TASK_RUNNING 0x0000 // 运行/就绪态Linux合并了 #define TASK_INTERRUPTIBLE 0x0001 // 可中断阻塞 #define TASK_UNINTERRUPTIBLE 0x0002 // 不可中断阻塞 #define __TASK_STOPPED 0x0004 // 暂停态 #define EXIT_ZOMBIE 0x0020 // 僵尸态 #define EXIT_DEAD 0x0040 // 死亡态1. 运行态Running / TASK_RUNNING第一层・定义级是什么进程正在 CPU 上执行或者已经准备好随时可以被调度执行。⚠️ 注意Linux 把 运行中 和 就绪 合并成了同一个状态TASK_RUNNING这是和教科书最大的区别有什么用标记这个进程是调度器的候选对象会被放进运行队列runqueue里等待 CPU 时间片。第二层・原理级底层实现每个 CPU 有一个 CFS完全公平调度器运行队列cfs_rq所有TASK_RUNNING状态的进程按vruntime虚拟运行时间挂在红黑树上调度器每次挑 vruntime 最小的进程上 CPU 运行第三层・对比级运行中 vs 就绪Linux 内核层面不分但从 是否占用 CPU 的角度区分 —— 占用 CPU 的叫 running在队列里排队的叫 ready时间片耗尽进程用完时间片 → 重新入队状态不变还是 TASK_RUNNING只是从 CPU 上下来了2. 就绪态Ready第一层・定义级是什么进程万事俱备只等 CPU。所有资源都分配好了就差被调度器选中上 CPU 执行。有什么用区分 能跑但没轮到 和 根本跑不了阻塞 的进程调度器只从就绪队列里挑进程。第二层・原理级底层实现在 Linux 里就是TASK_RUNNING状态但当前不在 CPU 上的那些进程挂在每个 CPU 的 runqueue 红黑树上。进入就绪态的时机fork()创建完新进程初始化完成后阻塞的进程等到了事件IO 完成、信号到来被抢占的进程高优先级进程来了时间片用完的进第三层・对比级状态等待的资源能否被调度就绪只缺 CPU✅ 在 runqueue 里随时可调度阻塞缺 IO / 锁 / 事件❌ 不在 runqueue调度器看不到3. 阻塞态Blocked / Sleeping第一层・定义级是什么进程因为等待某个事件发生而主动放弃 CPU暂停执行。事件到来之前给它 CPU 也跑不了。两种阻塞可中断阻塞TASK_INTERRUPTIBLE等事件 收到信号也会唤醒比如sleep()、wait()不可中断阻塞TASK_UNINTERRUPTIBLE只能等事件信号都不响应比如磁盘 IO 进行中有什么用避免忙等busy waiting浪费 CPU让 CPU 去跑别的进程事件来了再唤醒。第二层・原理级底层怎么实现进程把自己从 runqueue 中移除把自己挂到某个等待队列wait_queue上修改 state 为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE调用schedule()主动触发调度让出 CPU唤醒时反向操作事件触发后等待队列上的进程被唤醒state 改回TASK_RUNNING重新加入 runqueue。为什么这么设计等待队列是 生产者 - 消费者 模型事件生产者如中断处理函数唤醒等待者不可中断阻塞存在的意义防止 IO 过程中被信号打断导致数据不一致比如写到一半的磁盘第三层・对比级阻塞类型唤醒条件典型场景ps 显示可中断事件发生 任意信号sleep、wait、读终端S不可中断只能是事件发生磁盘 IO、锁 SemaphoreDDemo阻塞态观察// demo_block.c #include stdio.h #include unistd.h #include sys/types.h int main() { printf(PID: %d, 我马上进入 sleep可中断阻塞...\n, getpid()); printf(另开终端执行: ps -o pid,stat,cmd -p %d\n, getpid()); sleep(30); // 睡眠30秒状态为 S可中断睡眠 printf(睡醒了结束\n); return 0; }gcc demo_block.c -o demo_block ./demo_block # 另一个终端ps -o pid,stat,cmd -p pid # 会看到 STAT 是 S前台进程的可中断睡眠4. 僵尸态Zombie / EXIT_ZOMBIE第一层・定义级是什么进程已经执行结束退出了但它的父进程还没有调用wait()/waitpid()来收尸导致task_struct还没被释放。有什么用保留退出状态码和资源使用统计等父进程来 收尸 读取。僵尸进程本身几乎不占资源只占一个 PID 和一个 task_struct 结构体。第二层・原理级底层实现进程调用exit()→ 释放用户态资源地址空间、文件、内存状态设为EXIT_ZOMBIE给父进程发SIGCHLD信号父进程调用wait()读取退出状态后内核才释放 task_struct为什么这么设计父进程可能需要知道子进程是正常退出还是异常崩溃、退出码是多少、用了多少 CPU 时间这些信息必须在进程死后保留一段时间所以设计了 僵尸 这个中间状态第三层・对比级维度僵尸进程孤儿进程谁死了子进程死了父进程活着父进程死了子进程活着资源占用用户态资源已释放只剩 task_struct正常运行占完整资源危害大量僵尸占满 PID 号导致无法创建新进程无危害被 init 收养怎么解决父进程 wait或 kill 父进程让 init 接管不需要解决正常现象怎么杀僵尸进程→ 杀不了它已经死了。只能 kill 它的父进程让它变成孤儿然后被 init 进程收养并回收。Demo僵尸进程制造与观察// demo_zombie.c #include stdio.h #include stdlib.h #include unistd.h #include sys/types.h int main() { pid_t pid fork(); if (pid 0) { perror(fork失败); exit(1); } else if (pid 0) { // 子进程立刻退出变成僵尸 printf(子进程 PID%d 即将退出变成僵尸...\n, getpid()); exit(0); } else { // 父进程不 wait休眠30秒让你观察 printf(父进程 PID%d子进程 PID%d\n, getpid(), pid); printf(另开终端执行: ps -o pid,stat,cmd -p %d\n, pid); sleep(30); printf(父进程结束\n); } return 0; }gcc demo_zombie.c -o demo_zombie ./demo_zombie # 另一个终端ps aux | grep Z 或 ps -o pid,stat 子pid # 会看到 STAT 是 Z僵尸状态5. 孤儿态Orphan第一层・定义级是什么父进程先退出了子进程还在运行这个子进程就成了孤儿。有什么用不是故意设计的状态是一种现象。Linux 会自动把孤儿进程过继给 init 进程PID1由 init 来负责回收它的尸体保证不会永远僵尸。第二层・原理级底层实现父进程 exit 时遍历自己的所有子进程如果子进程还活着非 EXIT_DEAD就把它的父进程指针p-parent指向child_reaper通常是 init同时给新的父进程init发 SIGCHLD为什么这么设计必须有一个兜底机制否则父进程意外死亡后子进程退出时永远没人收尸PID 会泄漏init 进程天生自带 wait 循环专门收尸第三层・对比级对比项孤儿进程僵尸进程进程是否活着✅ 活着正常运行❌ 已死只剩壳占用资源完整的内存、文件、CPU 时间几乎不占只占 PID回收方式退出时由 init 自动回收必须父进程 wait 或父死被 init 收算不算问题不算系统自动处理大量累积才是问题PID 耗尽// demo_orphan.c #include stdio.h #include stdlib.h #include unistd.h #include sys/types.h int main() { pid_t pid fork(); if (pid 0) { perror(fork失败); exit(1); } else if (pid 0) { // 子进程 printf(子进程: PID%d, 父进程PPID%d\n, getpid(), getppid()); sleep(3); // 等父进程先死 printf(子进程: 现在我的PPID%d应该是1或systemd\n, getppid()); printf(子进程: 我是孤儿被init收养了\n); sleep(10); printf(子进程退出\n); } else { // 父进程立刻退出 printf(父进程: PID%d我先走一步\n, getpid()); exit(0); } return 0; }gcc demo_orphan.c -o demo_orphan ./demo_orphan # 观察子进程打印的 ppid 从父进程PID变成了1或systemd的PID

相关新闻

Godot PCK文件解析与资源提取全攻略:从工具使用到自定义解析器

Godot PCK文件解析与资源提取全攻略:从工具使用到自定义解析器

1. 项目概述:为什么我们需要关注PCK文件?如果你正在使用Godot引擎开发游戏,无论是独立小品还是商业大作,迟早会遇到一个绕不开的文件格式:.pck。这个看似不起眼的文件,实际上是Godot项目打包和分发的核心容…

2026/10/14 3:25:34 阅读更多 →
从创建到分享:微信群投票活动的详细步骤指南

从创建到分享:微信群投票活动的详细步骤指南

在微信群里发起一场投票评选,如今已成为班级评优、企业评先、社区互动乃至作品征集中的常见操作。但对于不熟悉工具的主办方来说,操作繁琐、广告干扰、数据难导出等问题时有发生。本文以“天天评选投票”为例,手把手带你走完从创建到分享的全…

2026/10/2 8:19:17 阅读更多 →
校园夏日风光摄影作品人气比拼投票制作

校园夏日风光摄影作品人气比拼投票制作

夏日校园,阳光穿过梧桐叶洒下斑驳光影,教学楼旁的凌霄花热烈绽放,操场上的少年奔跑出青春的模样。如果你正打算为学校组织一场“校园夏日风光摄影作品人气比拼”投票活动,却不知道从何下手,这篇测评文章或许能帮到你。…

2026/10/13 11:56:21 阅读更多 →

最新新闻

MySQL 从入门到实战(04):SQL 基础与一条查询的执行流程

MySQL 从入门到实战(04):SQL 基础与一条查询的执行流程

SQL 基础与执行流程 本篇所有 SQL 在本机 MySQL 8.0.46 实测。 核心问题:你敲下回车后,MySQL 到底做了什么? 理解这条链路,才知道索引该加在哪、为什么有些 SQL 慢。 一、一条 SQL 的完整生命周期 #mermaid-svg-o1uI88gGmZdgQ5sW{font-family:"trebuchet ms",ver…

2026/10/14 3:25:35 阅读更多 →
栈与队列:从原理到应用

栈与队列:从原理到应用

文章目录1. 引言2. 栈(Stack):后进先出的线性表3. 队列(Queue):先进先出的线性表4. 代码实现示例栈的实现代码5. 栈与队列的对比总结6. 总结与学习建议1. 引言 栈和队列是计算机科学中最基础、也最常用的两…

2026/10/14 3:25:35 阅读更多 →
# 京东客服离线自动回复怎么设置?叮当小宝CS补上夜间与高峰的接待缺口

# 京东客服离线自动回复怎么设置?叮当小宝CS补上夜间与高峰的接待缺口

京东的考核里,回复速度和应答率都算分。客服下班、午休或者大促期间排队太长时,买家的咨询不能一直挂着——离线自动回复就是兜底的那一道。这篇把入口、生效范围和常见的「配了但没用」讲清楚,再给一套补位做法。## 先分清两个入口&#xff…

2026/10/14 3:25:35 阅读更多 →
MySQL 从入门到实战(03):数据类型与建表规范

MySQL 从入门到实战(03):数据类型与建表规范

数据类型与建表规范 本篇所有 SQL 在本机 MySQL 8.0.46 实测。 核心问题:为什么金额要用 DECIMAL 而不是 FLOAT?VARCHAR(255) 是不是越大越好? 一、一个真实的踩坑:浮点数存金额 先看实测结果: CREATE TABLE demo.t_money_bad (id INT PRIMARY KEY AUTO_INCREMENT,amoun…

2026/10/14 3:25:35 阅读更多 →
COBOL报表开发实战:物理布局、文件绑定与状态机生命周期

COBOL报表开发实战:物理布局、文件绑定与状态机生命周期

简介:本资源是一份面向COBOL初学者与金融/政务系统维护人员的报表开发实践指南,聚焦COBOL环境下的结构化报表生成全流程。内容以真实可运行的rpt001程序为核心,完整呈现ID、Environment、Data(含File Section与Working-Storage&am…

2026/10/14 3:25:35 阅读更多 →
TikTok Shop 多店铺:平台侧哪些信息会被交叉比对

TikTok Shop 多店铺:平台侧哪些信息会被交叉比对

一、先说结论:官方对「关联」的定义,比你想的宽 TikTok Shop 官方在卖家学习中心有一篇《关联账号风险指南》,原文写得很直白——平台对关联账号的判定,通常不是依据单一的重合信息,而是多项风险信号综合判断&#xff…

2026/10/14 3:24:35 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →