Linux进程:僵尸与孤儿
一个C++程序,以main函数的return 0退出。真正的运行机制是:gcc
在链接的时候,会在程序的结尾加入sys_exit系统调用。
运行时,进程执行sys_exit,发送SIGCHLD信号给父进程,然后,进程进入僵尸状态,变成僵尸进程,等父进程收尸。
这样就出来两个问题:
1.
如果子进程在执行sys_exit时,父进程已经死亡怎么办?
2.
如果子进程退出时,父进程不收尸怎么办?
“子存父先死,孙在祖乃丧”,如果父进程在子进程调用sys_exit之前已经死亡,子进程在执行sys_exit时,发的SIGCHLD信号就无人接收了。谁给子进程收尸呢?
托孤
答案是“托孤”,武侠小说的主角,往往在要死的时候,将主角托付给一个很牛的人,然后就去了。当一个进程的父进程在这个进程退出前退出的话,就会把这个进程的父进程修改为一个可以“托孤”的很牛的进程,在Linux下,这个进程是PID为1的init进程,每个进程在死亡前,都会把自己的子进程”托孤“给init进程。
在Linux0.11内核源代码的linux/kernel/exit.c的do_exit函数中,有这样一段”托孤“的代码:
108
for (i=0 ; i<NR_TASKS ; i++)
109 if (task[i] &&
task[i]->father == current->pid) {
110
task[i]->father = 1;
僵尸
进程在退出后就立刻变成了僵尸,然后等父进程收尸;
如果这时它的父进程已经死了,也就是说这个进程是个孤儿,也没问题,它的父进程临死前”托孤“的init进程,也就是它的养父,会帮它收尸。
如果这里它的父进程还没死,就要看这个父进程在做什么了?如果这个父进程对正在调用wait或waitpid操作,则表示这个父进程有准备棺材纸钱,这个进程就可以入土为安了。或者这个父进程设置了SIGCHLD信号处理函数,并在处理函数中执行了wait或waitpid操作,也没问题。但如果父进程没有忙得不可开交,没有任何收尸的想法,那这个进程就只好一直处于僵尸态,直到父进程什么时候想起来的时候进行wait或waitpid收尸,或者父进程死的时候收尸。
在linux0.11内核源代码linux/kernel/exit.c的do_exit函数中,有这样一段"收尸"的代码
111
if (task[i]->state == TASK_ZOMBIE)
112 /*
assumption task[1] is always init */
113
(void) send_sig(SIGCHLD, task[1], 1);
但是,从子进程死亡,到父进程执行wai或死亡的这段时间内,子进程PID和
task_struct
就会一直被占用。
总结:
孤儿进程,就是子存父先死,进程退出时父进程已经退出,由养父收尸的进程。
僵尸进程,就是退出时父进程没有退出,但父进程也没有及时收尸的进程。会耗用一定时间的PID与task_struct资源。
Linux进程:僵尸与孤儿
一个C++程序,以main函数的return 0退出。真正的运行机制是:gcc
在链接的时候,会在程序的结尾加入sys_exit系统调用。
运行时,进程执行sys_exit,发送SIGCHLD信号给父进程,然后,进程进入僵尸状态,变成僵尸进程,等父进程收尸。
这样就出来两个问题:
1.
如果子进程在执行sys_exit时,父进程已经死亡怎么办?
2.
如果子进程退出时,父进程不收尸怎么办?
“子存父先死,孙在祖乃丧”,如果父进程在子进程调用sys_exit之前已经死亡,子进程在执行sys_exit时,发的SIGCHLD信号就无人接收了。谁给子进程收尸呢?
托孤
答案是“托孤”,武侠小说的主角,往往在要死的时候,将主角托付给一个很牛的人,然后就去了。当一个进程的父进程在这个进程退出前退出的话,就会把这个进程的父进程修改为一个可以“托孤”的很牛的进程,在Linux下,这个进程是PID为1的init进程,每个进程在死亡前,都会把自己的子进程”托孤“给init进程。
在Linux0.11内核源代码的linux/kernel/exit.c的do_exit函数中,有这样一段”托孤“的代码:
108
for (i=0 ; i<NR_TASKS ; i++)
109 if (task[i] &&
task[i]->father == current->pid) {
110
task[i]->father = 1;
僵尸
进程在退出后就立刻变成了僵尸,然后等父进程收尸;
如果这时它的父进程已经死了,也就是说这个进程是个孤儿,也没问题,它的父进程临死前”托孤“的init进程,也就是它的养父,会帮它收尸。
如果这里它的父进程还没死,就要看这个父进程在做什么了?如果这个父进程对正在调用wait或waitpid操作,则表示这个父进程有准备棺材纸钱,这个进程就可以入土为安了。或者这个父进程设置了SIGCHLD信号处理函数,并在处理函数中执行了wait或waitpid操作,也没问题。但如果父进程没有忙得不可开交,没有任何收尸的想法,那这个进程就只好一直处于僵尸态,直到父进程什么时候想起来的时候进行wait或waitpid收尸,或者父进程死的时候收尸。
在linux0.11内核源代码linux/kernel/exit.c的do_exit函数中,有这样一段"收尸"的代码
111
if (task[i]->state == TASK_ZOMBIE)
112 /*
assumption task[1] is always init */
113
(void) send_sig(SIGCHLD, task[1], 1);
但是,从子进程死亡,到父进程执行wai或死亡的这段时间内,子进程PID和
task_struct
就会一直被占用。
总结:
孤儿进程,就是子存父先死,进程退出时父进程已经退出,由养父收尸的进程。
僵尸进程,就是退出时父进程没有退出,但父进程也没有及时收尸的进程。会耗用一定时间的PID与task_struct资源。
发布评论