Unix进程模型中,进程是按照父进程产生子进程,子进程产生子子进程这样的方式创建出完成各项相互协作功能的进程的。当一个进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。
那么孤儿进程是什么呢?
1 孤儿进程
孤儿进程就是父进程先于子进程终止,这时子进程就是【孤儿进程】,会被init收养。
先熟悉一个命令:查看进程状态
ps ajx
执行
依次是父进程id、进程id、组进程id、会话进程id
这里只要关注父进程id和进程id即可,
模拟父进程先于子进程终止
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid = fork();
// 子进程执行
if (pid == 0) {
while (1) {
printf("I'm child, my pid = %d, my parent pid = %d\n", getpid(), getppid());
sleep(2);
}
} else if (pid > 0) {
// 父进程执行
printf("I'm parent, my pid = %d\n", getpid());
sleep(9);
printf("==============I'm going to die=========\n");
} else if (pid == -1) {
// fork出错
perror("fork error");
exit(1);
}
return 0;
}
执行
可以看到有两个进程。子进程的PID是9714、父进程的PID是9713、父进程的父进程的PID是9630。
当父进程运行结束后,父进程PID变成1457。
查看1457进程
这里/lib/systemd/systemd --user 就是【孤儿收养院】
这时子进程(PID=9714)就是孤儿进程,它会一直执行。
怎么解决孤儿进程问题呢?
直接kill
kill -9 9714
2 僵尸进程
简单来说就是:子进程终止,父进程没有及时回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。
kill 对其无效。这里要注意,每个进程结束后都必然会经历僵尸态,时间长短的差别而已。
当一个进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。如果父进程没有这么做的话,会产生什么后果呢?此时,子进程虽然已经退出了,但是在系统进程表中还为它保留了一些退出状态的信息,如果父进程一直不取得这些退出信息的话,这些进程表项就将一直被占用,此时,这些占着茅坑不拉屎的子进程就成为“僵尸进程”(zombie)。系统进程表是一项有限资源,如果系统进程表被僵尸进程耗尽的话,系统就可能无法创建新的进程。
模拟子进程先于父进程终止。
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid = fork();
// 子进程执行
if (pid == 0) {
printf("I'm child,my pid = %d, my parent = %d\n",getpid(), getppid());
sleep(9);
printf("---------------I'm going to die-------------------\n");
} else if (pid > 0) {
while (1) {
printf("I'm parent, my pid = %d, my son pid = %d\n",getpid(), pid);
sleep(1);
}
} else if (pid == -1) {
perror("fork error");
exit(1);
}
return 0;
}
运行
子进程PID是10087,父进程PID是10086。
执行完之后,子进程运行结束,父进程一直打印循环语句。
子进程10087成为僵尸进程。
回收僵尸进程,得kill它的父进程,让它成为孤儿进程,让孤儿院去回收它。