在 Linux 系统编程中,进程(Process) 是操作系统进行资源分配和调度的基本单位。理解进程的概念是掌握系统编程、多任务处理、并发编程的基础。
目录
一、什么是进程?
定义:
二、进程的生命周期
示例:查看当前系统中的进程
三、进程的状态(STAT)
四、进程的父子关系与进程树
示例:查看进程树
关键概念:
五、进程标识符(PID 和 PPID)
示例:查看当前 shell 的 PID 和 PPID
六、前台进程与后台进程
示例:将进程放入后台运行
七、进程的优先级(Nice 值)
查看 nice 值:
设置 nice 值启动进程:
修改已有进程的 nice 值:
八、进程相关的系统调用(C语言接口)
九、第一个 C 程序:演示 fork() 创建进程
示例代码:process_example.c
编译并运行:
十、总结知识点图解(知识树状图)
十一、课后练习建议
一、什么是进程?
定义:
进程是一个程序的执行实例,包括:
- 程序代码(Text Segment)
- 当前活动(如寄存器的状态、程序计数器等)
- 数据段(Data Segment)
- 堆栈(Stack)
- 打开的文件、信号处理函数等资源
简单来说:一个正在运行的程序就是一个进程。
二、进程的生命周期
一个进程从创建到终止,会经历以下几个阶段:
+-------------------+
| 创建进程 | fork()
+-------------------+|v
+-------------------+
| 运行/就绪状态 |
+-------------------+|v
+-------------------+
| 阻塞(等待I/O等) |
+-------------------+|v
+-------------------+
| 终止或退出 | exit(), _exit()
+-------------------+
示例:查看当前系统中的进程
ps aux
输出示例(简化):
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.2 168944 9348 ? Ss 09:00 0:01 /sbin/init
user1 1234 0.1 0.5 500000 20000 ? Sl 09:10 0:02 /usr/bin/vim
各列含义简要说明:
列名 | 含义 |
---|---|
USER | 进程所有者 |
PID | 进程 ID |
%CPU | 占用 CPU 百分比 |
%MEM | 占用内存百分比 |
VSZ | 虚拟内存使用量(KB) |
RSS | 实际物理内存使用量(KB) |
TTY | 控制终端 |
STAT | 进程状态 |
START | 进程启动时间 |
TIME | 占用 CPU 时间总和 |
COMMAND | 启动命令 |
三、进程的状态(STAT)
Linux 中进程常见的状态有以下几种:
状态字符 | 含义 |
---|---|
R (Running) | 正在运行或准备运行 |
S (Sleeping) | 可中断的睡眠状态(等待某事件) |
D (Disk Sleep) | 不可中断的睡眠(通常在 I/O) |
Z (Zombie) | 僵尸进程(已结束但未被回收) |
T (Stopped) | 被停止(如收到 SIGSTOP) |
X (Dead) | 已死亡(不会出现在 ps 中) |
四、进程的父子关系与进程树
每个进程都有一个父进程(除了 init/systemd),通过 fork()
创建子进程。
示例:查看进程树
pstree
输出示例:
systemd─┬─NetworkManager───2*[{NetworkManager}]├─login───bash└─sshd───bash───vim
关键概念:
- 父进程(Parent Process):创建其他进程的进程。
- 子进程(Child Process):由父进程创建的进程。
- 僵尸进程(Zombie Process):子进程结束后,父进程没有调用
wait()
或waitpid()
获取其退出状态,该子进程变成僵尸进程。 - 孤儿进程(Orphan Process):父进程先于子进程结束,子进程成为孤儿进程,由
init
(PID=1)接管。
五、进程标识符(PID 和 PPID)
- PID(Process ID):进程的唯一标识号。
- PPID(Parent Process ID):父进程的 PID。
示例:查看当前 shell 的 PID 和 PPID
echo "Current PID: $$"
echo "Parent PID: $PPID"
输出示例:
Current PID: 12345
Parent PID: 11111
你也可以使用 ps
查看详细信息:
ps -p 12345 -o pid,ppid,comm
六、前台进程与后台进程
- 前台进程:占用终端,用户可以直接交互。
- 后台进程:不占用终端,通常用于长时间运行的任务。
示例:将进程放入后台运行
sleep 100 & # 在后台运行
查看后台进程:
jobs
七、进程的优先级(Nice 值)
Linux 使用 nice 值 来控制进程的优先级,默认值为 0,范围为 -20(最高优先级)到 19(最低优先级)。
查看 nice 值:
ps -l
设置 nice 值启动进程:
nice -n 10 sleep 100 &
修改已有进程的 nice 值:
renice 5 -p 12345
八、进程相关的系统调用(C语言接口)
这些是 Linux 编程中最常用的系统调用:
系统调用 | 功能描述 |
---|---|
fork() | 创建子进程 |
exec() 系列 | 替换当前进程为新程序 |
wait() | 等待子进程结束 |
exit() | 终止当前进程 |
getpid() | 获取当前进程的 PID |
getppid() | 获取父进程的 PID |
九、第一个 C 程序:演示 fork() 创建进程
示例代码:process_example.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main() {pid_t pid;printf("Before fork: This is the parent process (PID: %d)\n", getpid());pid = fork(); // 创建子进程if (pid < 0) {fprintf(stderr, "Fork failed\n");return 1;} else if (pid == 0) {// 子进程printf("This is the child process (PID: %d), Parent PID: %d\n", getpid(), getppid());} else {// 父进程printf("This is the parent process again (PID: %d), Child PID: %d\n", getpid(), pid);}return 0;
}
编译并运行:
gcc process_example.c -o process_example
./process_example
输出示例(顺序可能不同):
Before fork: This is the parent process (PID: 12345)
This is the parent process again (PID: 12345), Child PID: 12346
This is the child process (PID: 12346), Parent PID: 1
注意:由于父进程和子进程是并发执行的,所以输出顺序可能不确定。
十、总结知识点图解(知识树状图)
进程的概念
│
├── 什么是进程?
│ ├── 程序的执行实例
│ └── 包含代码、数据、堆栈、资源等
│
├── 进程生命周期
│ ├── 创建 → 运行 → 阻塞 → 终止
│ └── fork(), exec(), exit()
│
├── 进程状态(STAT)
│ ├── R/S/D/Z/T/X
│
├── 进程关系与进程树
│ ├── 父进程与子进程
│ ├── 僵尸进程 vs 孤儿进程
│ └── pstree 命令查看树结构
│
├── 进程标识符
│ ├── PID(当前进程ID)
│ └── PPID(父进程ID)
│
├── 前台进程 vs 后台进程
│ ├── jobs, &, fg, bg
│
├── 进程优先级(nice)
│ ├── nice, renice 命令
│
└── 进程相关系统调用(C语言)├── fork()├── exec()├── wait()├── exit()├── getpid()└── getppid()
十一、课后练习建议
- 使用
ps
命令查找当前运行的所有bash
进程。 - 写一个 Shell 脚本,在后台运行多个
sleep
命令,并使用jobs
查看它们的状态。 - 编写一个 C 程序,使用
fork()
创建两个子进程,分别打印不同的信息。 - 尝试使用
nice
和renice
修改某个进程的优先级。