inux 进程管理笔记
一、父子进程关系
1. 进程复制机制
-
子进程是父进程的副本
-
Linux 2.6之后(如Ubuntu 18,Linux 5.4) :采用**写时复制(Copy-On-Write,COW)**技术
-
fork完成后:子进程共享父进程的所有内存空间
-
写时复制触发时机:当父子进程中的任何一方尝试修改某个变量或内存区域时,才会为子进程开辟新的内存空间
2. 进程终止的8种情况
正常终止:
-
main函数中的return
-
exit() - C库函数
-
执行I/O库的清理工作
-
关闭所有流和已打开的文件
-
执行清理函数(atexit注册的函数)
-
-
_exit() / _Exit() - 系统调用
-
关闭所有已打开的文件
-
不执行清理函数
-
-
主线程退出
-
主线程调用pthread_exit()
异常终止:
-
abort() - 产生SIGABRT信号
-
信号终止 - signal/kill发送信号
-
最后一个线程被pthread_cancel()
二、进程退出后的状态
1. 僵尸进程(Zombie)
-
产生条件:子进程先于父进程终止
-
状态特征:
-
用户内存空间已释放
-
进程不会被调度执行
-
但内核中的PCB(进程控制块)未被释放
-
-
危害:长时间运行的父进程多次创建子进程时,可能导致内核空间积累大量僵尸进程PCB,引发系统不稳定或崩溃
-
查看命令 :
ps或top
2. 孤儿进程(Orphan)
-
产生条件:父进程先于子进程终止
-
处理机制:
-
子进程会被init进程(PID=1)接管
-
由新的父进程(init)负责回收资源
-
通常无需特别关注
-
三、退出函数详解
1. exit() - 库函数
void exit(int status);
-
功能:让进程退出,并刷新缓冲区
-
参数:
-
status:进程退出状态 -
常用值:
EXIT_SUCCESS(0)、EXIT_FAILURE(1)
-
-
执行流程:
-
刷新缓冲区
-
执行atexit()注册的退出函数
-
调用_exit()系统调用
-
2. _exit() - 系统调用
void _exit(int status);
-
功能 :让进程退出,不刷新缓冲区
-
参数 :
status- 进程退出状态
3. return关键字的区别
-
在main函数中:结束整个进程
-
在其他函数中:仅结束当前函数
四、进程状态回收
1. wait()函数
pid_t wait(int *status);
-
功能:阻塞等待任意子进程退出,并回收其状态
-
特点:
-
只能由父进程调用
-
一次只能回收一个子进程
-
-
参数:
-
status:存储子进程退出状态 -
不关心状态时可传入
NULL
-
-
返回值:
-
成功:回收的子进程PID
-
失败:-1
-
2. 状态检查宏
| 宏 | 功能 | 说明 |
|---|---|---|
WIFEXITED(status) |
检查是否正常终止 | 返回非0表示正常结束 |
WEXITSTATUS(status) |
获取退出状态值 | 正常终止时使用 |
WIFSIGNALED(status) |
检查是否信号终止 | 返回非0表示信号终止 |
WTERMSIG(status) |
获取终止信号编号 | 信号终止时使用 |
3. 使用示例
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
// 子进程
exit(42); // 正常退出,状态码42
} else {
// 父进程
int status;
wait(&status);
if (WIFEXITED(status)) {
printf("子进程正常退出,返回值:%d\n",
WEXITSTATUS(status)); // 输出:42
}
if (WIFSIGNALED(status)) {
printf("子进程被信号终止,信号:%d\n",
WTERMSIG(status));
}
}
return 0;
}
五、进程空间回收的重要性
1. 僵尸进程的危害
-
内核PCB空间被占用,无法释放
-
大量僵尸进程可能导致内核内存不足
-
影响系统稳定性和性能
2. 回收策略
-
父进程应主动调用
wait()或waitpid()回收子进程 -
对于需要多次创建子进程的服务进程,必须正确回收
-
可使用信号处理函数(如SIGCHLD)异步回收
六、总结要点
-
写时复制是现代Linux的优化机制,减少不必要的内存复制
-
区分正常终止与异常终止的不同处理方式
-
exit()和_exit()的主要区别在于缓冲区刷新和清理函数执行
-
僵尸进程需要父进程主动回收,否则会长期占用系统资源
-
wait()系列函数是进程回收的标准方法
-
状态检查宏帮助父进程了解子进程的终止原因
注意事项:
-
在生产环境中,应确保所有子进程都被正确回收
-
对于服务器程序,建议设置SIGCHLD信号处理
-
使用
waitpid()可以更灵活地控制回收行为(如非阻塞模式)