Linux-进程
·
目录
PCB(Process Control Block):进程控制块,包含进程的所有管理信息
一、基本概念
1.1 什么是进程?
- 进程是正在进行中的程序
- 是程序的一次执行过程
- 是程序的执行实例
1.2 进程 vs 程序

二、为什么需要进程?
核心目的
提高 CPU 利用效率,实现多任务处理。
2.1 单片机 vs 操作系统
- 单片机:单道程序,只能运行一个程序(
while(1){}) - 操作系统:多道程序,可同时运行多个程序
2.2 并发与并行
- 宏观并行:用户角度看,多个程序“同时”运行
- 微观串行:CPU 在多个进程间快速切换
- 时间片轮转:每个进程获得一小段 CPU 时间(如 10~100ms)
- 分时复用:通过调度算法,让多个进程看起来同时运行
三、进程的组成
3.1 C 程序内存布局(5 个区)

3.2 进程 = PCB + 内存空间

PCB(Process Control Block):进程控制块,包含进程的所有管理信息
- 进程 ID(PID)
- 进程状态(就绪、运行、阻塞等)
- 程序计数器(PC)
- CPU 寄存器
- 内存管理信息
- I/O 状态信息
四、进程的状态
4.1 三态模型
- 就绪态(Ready):等待 CPU 调度
- 执行态(Running):正在 CPU 上运行
- 阻塞态(Blocked):等待事件(如 I/O 完成)
4.2 Linux 进程状态(ps 命令显示)

五、进程相关命令
5.1 查看进程
top # 动态查看进程(CPU、内存使用等)
ps aux | grep a.out # 查看特定进程快照
ps -eLf | grep a.out # 查看 PID 和 PPID(父进程 ID)
pstree -sp <pid> # 查看进程树及父子关系
5.2 控制进程
kill -l # 查看所有信号
kill -9 <pid> # 强制杀死(SIGKILL)
kill -19 <pid> # 暂停(SIGSTOP)
kill -18 <pid> # 继续(SIGCONT)
killall a.out # 按名称杀死所有同名进程
六、进程创建 —— fork()
6.1 函数原型
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
6.2 功能
- 复制调用进程(父进程)创建新进程(子进程)
- 子进程是父进程的副本,但有独立的内存空间
6.3 返回值
- 父进程:返回子进程的 PID(> 0)
- 子进程:返回 0
- 失败:返回 -1
基本用法
pid_t pid = fork();
if (pid < 0)
{
perror("fork fail");
return -1;
}
if (pid > 0)
{
// 父进程逻辑
}
else if (pid == 0)
{
// 子进程逻辑
}
6.4 重要特性
- 执行顺序不确定:由操作系统调度决定
- 独立内存空间:数据互不影响(写时复制)
- 共享代码段:父子进程执行相同代码
- 文件描述符继承:子进程继承父进程打开的文件
多次 fork 进程数计算(面试题):
第一次 fork → 2 个进程(父 + 子1)
第二次 fork → 4 个进程(父、子1 各自 fork 一次)
规律:n 次 fork → 2^n 个进程
循环创建多个子进程(关键):
for (int i = 0; i < n; i++)
{
pid = fork();
if (pid < 0)
{
perror("fork fail");
return -1;
}
if (pid == 0)break; // 子进程立即跳出,避免子进程再 fork
}
// 用 i 的值区分每个子进程的任务
七、exec 函数族 —— 执行新程序
7.1 为什么需要 exec?
fork后子进程执行与父进程相同代码- 若想执行完全不同程序,需用
exec
7.2 exec 函数族
#include <unistd.h>
int execl(const char *path, const char *arg, ...); // 参数逐个列出
int execv(const char *path, char *const argv[]); // 参数用数组
int execlp(const char *file, const char *arg, ...); // 在 PATH 中查找
int execvp(const char *file, char *const argv[]); // 数组 + PATH 查找
7.3 示例:execvp
char *arg[] = {"ls", "-l", ".", NULL};
execvp("ls", arg); // 无需完整路径
⚠️
exec成功后不返回,当前进程代码段被替换!
八、进程退出
8.1 退出方式
- 正常退出:
return 0、exit()、_exit() - 异常退出:收到信号(如 SIGKILL)、调用
abort()
8.2 exit() vs _exit()

九、进程资源回收 —— wait / waitpid
9.1 僵尸进程 vs 孤儿进程
| 类型 | 定义 | 危害 | 处理方式 |
|---|---|---|---|
| 孤儿进程 | 父进程先结束,子进程还在运行 | 无危害 | 被 init(PID=1)收养 |
| 僵尸进程 | 子进程已结束,父进程未回收其 PCB | 占用 PID 和内存资源 | 必须用 wait 回收 |
9.2 wait() 函数
#include <sys/wait.h>
pid_t wait(int *wstatus); // 阻塞等待任意子进程退出
状态判断宏:
WIFEXITED(wstatus) // 是否正常退出?
WEXITSTATUS(wstatus) // 获取退出状态码(0~255)
WIFSIGNALED(wstatus) // 是否被信号终止?
WTERMSIG(wstatus) // 获取终止信号编号
9.3 waitpid() 函数(更灵活)
pid_t waitpid(pid_t pid, int *wstatus, int options);
pid > 0:等待指定 PID 的子进程options = WNOHANG:非阻塞(立即返回)
进程生命周期
1.创建(fork) → 2. 执行(子承父业 or exec 自立门户)→ 3. 退出(exit) → 4. 回收(wait/waitpid)
重要函数速查

更多推荐

所有评论(0)