各类资料学习下载合集
链接:https://pan.quark.cn/s/7c8c391011eb
在操作系统的世界里,每一个运行的程序都是一个鲜活的“生命体”——进程。它们从诞生(创建)到消亡(终止),会经历一系列不同的状态。理解这些状态及其转换机制,是深入掌握操作系统原理、进行性能调优和问题排查的关键。
今天,就让我们跟随课堂笔记,通过生动的代码实例,一起探索进程的生命周期,揭开“进程状态”的神秘面纱。
一、进程状态的五态模型
尽管不同教材对进程状态的划分略有差异(四态或五态),但其核心思想是一致的。我们以更完整、更经典的五态模型为基础进行讲解:
初始态 (New/Initial): 进程刚刚被创建,操作系统已为其分配了PCB(进程控制块),但尚未加载到内存或完成其他必要的初始化。这是一个非常短暂的过渡状态。就绪态 (Ready): 进程已经“万事俱备,只欠东风”。它获取了除CPU之外的所有必需资源(如内存),并被加载到内存中,随时准备被CPU调度执行。运行态 (Running): 进程成功获得了CPU时间片,其指令正在CPU上执行。挂起态 (Blocked/Suspended): 进程因等待某个事件的发生而主动放弃CPU。这个事件不是CPU资源,而是像等待用户输入、等待磁盘I/O完成、等待网络数据等。终止态 (Terminated/Exit): 进程执行完毕或被系统终止,其占有的资源将被回收,但PCB信息可能暂时保留,等待父进程读取其退出状态。
(这是一个示意图,帮助理解状态转换关系)
二、状态转换的实践与代码演示
理论知识略显枯燥,让我们用代码让这些状态“活”起来。我们将通过编写简单的C程序,并结合Linux的 命令来亲眼观察这些状态。
ps
命令输出的
ps aux 列就是我们观察的重点,常见的状态码有:
STAT
R (Running or Runnable): 运行态或就绪态。S (Interruptible Sleep): 可中断的睡眠状态(挂起态的一种)。T (Stopped): 停止状态。Z (Zombie): 僵尸状态(终止态的一种)。
1. 运行态 (R) – CPU密集型任务
一个持续进行计算、几乎不需要等待其他资源的进程,会长时间处于运行态或就绪态。
代码案例:
running_process.c
#include <stdio.h>
int main() {
printf("CPU-intensive process started. PID is %d
", getpid());
// 一个无限循环,持续占用CPU
while (1) {
// No operation, just spinning the CPU
}
return 0;
}
编译与运行:
打开一个终端(我们称之为终端A):
# 编译
gcc running_process.c -o running_process
# 运行
./running_process
程序会卡住,因为它陷入了死循环。现在,打开另一个终端(终端B),使用 命令查找并观察它的状态。
ps
运行结果 (在终端B中查看):
# 使用grep过滤出我们的进程
ps aux | grep running_process
你会看到类似下面的输出:
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
myuser 12345 99.9 0.0 4321 800 pts/0 R+ 11:30 0:15 ./running_process
结果分析: 列显示为
STAT。
R+ 代表该进程正处于运行态或就绪态(在多核CPU上,它可能正在某个核心上运行;在单核上,它可能在就绪队列和运行状态间快速切换)。
R 表示它是一个前台进程。
+
提示:在终端A中按
可以终止该进程。
Ctrl+C
2. 挂起态/阻塞态 (S) – 等待I/O
当进程需要等待外部资源时,如用户输入,它会进入挂起态(睡眠状态),主动让出CPU。
代码案例:
sleeping_process.c
#include <stdio.h>
#include <unistd.h> // for sleep()
int main() {
printf("Process will sleep for 30 seconds. PID is %d
", getpid());
// 调用sleep函数,进程将挂起30秒
sleep(30);
printf("Process woke up and is now finishing.
");
return 0;
}
编译与运行 (在终端A):
gcc sleeping_process.c -o sleeping_process
./sleeping_process
运行结果 (在终端B中查看):
在程序打印第一句话后的30秒内,在终端B中执行:
ps aux | grep sleeping_process
输出结果如下:
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
myuser 12348 0.0 0.0 4321 780 pts/0 S+ 11:35 0:00 ./sleeping_process
结果分析: 列显示为
STAT。
S+ 代表可中断睡眠(Interruptible Sleep),这是最常见的挂起状态。进程正在等待
S 函数的计时结束,此时它不消耗任何CPU资源,从而提高了系统整体的CPU利用率。
sleep
3. 停止态 (T) – 被暂停的进程
进程可以被信号暂停(Stop),此时它会进入停止态,直到收到继续执行的信号。
代码案例:
我们复用之前的 程序。
running_process
操作步骤 (在终端A):
# 在后台运行我们的CPU密集型程序,注意末尾的 '&'
./running_process &
终端会打印出它的PID。
[1] 12350
CPU-intensive process started. PID is 12350
运行结果 (在终端A中操作和观察):
# 1. 查看初始状态,应该是 R
ps aux | grep 12350
# 2. 发送STOP信号,使其暂停 (请将12350替换为你的实际PID)
kill -STOP 12350
# 3. 再次查看状态,应该变为 T
ps aux | grep 12350
# 4. 发送CONT信号,使其恢复运行
kill -CONT 12350
# 5. 最后查看状态,应该又变回 R
ps aux | grep 12350
# 6. 结束进程
kill -9 12350
运行结果截图:
# 步骤1的结果
myuser 12350 99.9 0.0 4321 800 pts/0 R 11:40 0:25 ./running_process
# 步骤3的结果
myuser 12350 0.0 0.0 4321 800 pts/0 T 11:40 0:25 ./running_process
# 步骤5的结果
myuser 12350 98.5 0.0 4321 800 pts/0 R 11:41 0:38 ./running_process
结果分析: 通过发送 和
SIGSTOP 信号,我们成功地让一个进程在运行态(R)和停止态(T)之间切换。这在调试或系统管理中非常有用。
SIGCONT
4. 终止态 (Z) – “僵尸”进程
当一个子进程结束,但其父进程没有回收它(通过 或
wait() 系统调用),这个子进程就会变成一个“僵尸”进程。它已经释放了所有资源,但在进程表中仍然保留一个条目,包含其PID和退出状态,等待父进程读取。
waitpid()
代码案例:
zombie_process.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
// fork失败
perror("fork failed");
exit(1);
} else if (pid == 0) {
// 这是子进程
printf("I am the child (PID: %d), and I am exiting now.
", getpid());
exit(0); // 子进程立即退出
} else {
// 这是父进程
printf("I am the parent (PID: %d), child is %d.
", getpid(), pid);
printf("Parent is sleeping for 30 seconds, not waiting for the child.
");
sleep(30); // 父进程睡眠,不回收子进程
printf("Parent is waking up and exiting.
");
}
return 0;
}
编译与运行 (在终端A):
gcc zombie_process.c -o zombie_process
./zombie_process
运行结果 (在终端B中查看):
在父进程睡眠的30秒内,在终端B中执行:
ps aux | grep zombie_process
你会看到两个进程,其中一个状态为 :
Z+
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
myuser 12360 0.0 0.0 4321 800 pts/0 S+ 11:50 0:00 ./zombie_process
myuser 12361 0.0 0.0 0 0 pts/0 Z+ 11:50 0:00 [zombie_process] <defunct>
结果分析: PID为 的进程状态为
12361,并且其COMMAND后面带有
Z+ 标志,这正是典型的僵尸进程。它不占用内存或CPU,但会占用一个进程号。大量的僵尸进程可能会耗尽系统可用的PID,导致无法创建新进程。
<defunct>
三、知识小结
最后,我们将课堂笔记的核心内容整理成表格,方便您回顾和记忆:
|
知识点 |
核心内容 |
考试重点 / 易混淆点 |
|
进程状态划分 |
初始态、就绪态、运行态、挂起态(阻塞态)、终止态(停止态)。 |
状态数量可变(4种或5种),核心是理解每个状态的定义。 |
|
就绪态 |
万事俱备,只等CPU。 |
与挂起态的核心区别:就绪态等待的是CPU,挂起态等待的是其他资源(如I/O)。 |
|
运行态 |
正在CPU上执行指令。 |
可能因时间片用完(被动)返回就绪态,或因等待资源(主动)进入挂起态。 |
|
挂起态(阻塞态) |
主动放弃CPU,等待非CPU资源。 |
这是提高CPU利用率的关键设计,避免CPU在等待时空转。 |
|
终止态 |
进程结束,等待父进程回收。 |
如果父进程未回收,会产生僵尸进程(Zombie)。 |
|
状态转换逻辑 |
运行↔就绪(调度);运行→挂起(I/O等待);挂起→就绪(资源就绪)。 |
理解状态转换的触发条件是面试和考试的重点。 |
进程状态是操作系统管理和调度进程的基础。通过今天的代码实践,我们不仅理解了理论模型,更亲眼见证了进程在不同状态间的“舞蹈”。希望这趟从诞生到消亡的进程生命周期之旅,能让你对操作系统的认知更上一层楼!




