Days 30 进程
·
一、进程基础概念
1. 程序与进程区别
- 程序:存放在磁盘(外存)上的可执行文件,属于静态文件。
- 进程:程序的一次动态执行实例,操作系统把程序加载到内存运行,拥有创建、调度、消亡完整生命周期。
同一个程序可以多次运行,生成多个相互独立的进程。
2. 进程常用 shell 命令
表格
| 命令 | 作用 |
|---|---|
ps -ef |
查看全量进程信息,展示 PID、PPID |
ps -aux |
查看进程 CPU、内存占用情况 |
pstree |
查看进程树,观察父子进程关系 |
top |
实时查看进程资源占用 |
kill -9 pid |
强制杀死指定 PID 进程 |
killall -9 程序名 |
杀死该程序产生的全部进程 |
./a.out & |
将程序放到后台运行 |
jobs |
查看当前终端的后台任务 |
fg 编号 |
把后台任务切换到前台执行 |
- PID:进程 ID,操作系统分配,每个进程唯一标识。
- PPID:父进程 ID,代表创建当前进程的父进程 PID。
3. 进程内存布局
进程被操作系统加载到内存,内存分为 5 大区域:
- 文本段 (.text):存放程序二进制代码、指令,只读。
- 数据段 (.data):已经初始化的全局变量、static 静态变量。
- bss 段:未初始化全局 / 静态变量,程序启动自动置 0。
- 栈 (stack):局部变量、函数形参、函数调用栈帧;函数退出自动回收;空间小,由系统自动管理。
- 堆 (heap):
malloc / calloc / realloc手动申请,必须free手动释放;空间大,使用不当容易产生内存泄漏。
重点记忆:局部变量存放在栈;全局 /static 变量存放在数据段 /bss;malloc 申请的内存全部在堆区。
4. 获取自身 PID、PPID 系统调用
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void); // 获取自己进程PID
pid_t getppid(void); // 获取父进程PID
二、fork () 创建子进程(重中之重)
函数原型
#include <unistd.h>
pid_t fork(void);
返回值规则(fork 最核心:一次调用,两次返回)
-1:fork 失败,子进程创建失败。0:当前代码运行在子进程中。>0:当前代码运行在父进程中,返回值就是新创建子进程的 PID。
💡核心原理:fork 之后子进程复制父进程的代码、数据、堆、栈、文件描述符;采用写时复制机制,只有内存发生修改的时候,才会真正拷贝物理内存,提升效率。
示例代码:1 父 1 子
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
int main(void)
{
pid_t pid;
pid = fork();
if(-1 == pid)
{
perror("fork");
return -1;
}
if(0 == pid)
{
//子进程执行分支
printf("子进程: pid=%d, ppid=%d\n",getpid(),getppid());
}
else
{
//父进程执行分支
printf("父进程: pid=%d, 子pid=%d\n",getpid(),pid);
}
return 0;
}
经典坑点:连续两次 fork
pid1 = fork();
pid2 = fork();
执行两次 fork,一共产生
2^2 = 4个进程! 父进程创建子 1;父、子 1 都会继续执行第二个 fork,分别再生子 2、子 3。 如果只想实现1 个父进程创建 2 个子进程:子进程内部必须exit(0)或者return 0,阻止子进程继续向下执行第二个 fork。
子进程退出方式
exit(0):任意函数内结束进程;0 代表正常退出,非 0 代表异常退出。_exit():纯系统调用,直接退出,不会刷新 IO 缓冲区。return 0;:只在 main 函数中等价于 exit (0);普通函数里面 return 只是函数返回,不会结束进程。
❗注意:
break只能跳出循环 /switch,不能结束进程,不能用来代替 exit。
三、进程回收 wait /waitpid
- 僵尸进程 (Zombie):子进程先退出,父进程没有调用接口回收子进程资源,子进程 PCB 控制块残留在内核。
- 孤儿进程:父进程先退出,子进程失去父进程,会被系统
init/systemd进程收养。
1.wait()
#include <sys/wait.h>
pid_t wait(int *wstatus);
- 阻塞等待任意一个子进程结束;获取子进程退出状态,释放子进程 PCB 资源,消除僵尸进程。
- 返回值:成功返回退出子进程 PID;失败返回‑1。
- 参数 wstatus:传出参数,保存子进程退出状态,可以配合宏解析:
WIFEXITED(status):子进程正常退出则为真WEXITSTATUS(status):拿到子进程 exit 传递的返回值
2.waitpid ()(实际开发优先使用,可以设置非阻塞)
pid_t waitpid(pid_t pid, int *wstatus, int options);
pid 参数:
- pid>0:等待指定 PID 的子进程
- pid=-1:等待任意子进程,效果等价 wait
options 选项:
0:阻塞模式WNOHANG:非阻塞,没有子进程结束立刻返回 0,不会卡住父进程。
项目中优先使用 waitpid + WNOHANG,避免父进程被无限阻塞。
更多推荐

所有评论(0)