1. 概念:
在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程,无法正常结束,此时即使是root身份kill -9也不能杀死僵尸进程。补救办法是杀死僵尸进程的父进程(僵尸进程的父进程必然存在),僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程.
2. 本质:
所谓以root身份也不能杀死僵尸进程,其实只是用户态的感觉。真正原因是这个进程在内核看来已经结束了,你不能杀死一个死人,不是吗。内核维护了一些状态信息,等待其父进程获取这些状态信息,除非父进程明确表示它不想获取这些状态信息。
3. 处理:
- 显式忽略SIGCHLD信号是指类似这样的代码:
signal( SIGCHLD, SIG_IGN );
- 安装SIGCHLD信号句柄是指类似这样的代码:
static
void
on_sigchld (
int
signo )
... {
pid_t pid;
int status;
while ( ( pid = waitpid( -1, &status, WNOHANG ) ) > 0 )
...{
/**//*
* 演示用,不推荐在信号句柄中使用fprintf()
*/
fprintf( stderr, "child <%u> terminated", ( unsigned int )pid );
}
return;
} /**/ /* end of on_sigchld */
... ...
signal( SIGCHLD, on_sigchld );
... {
pid_t pid;
int status;
while ( ( pid = waitpid( -1, &status, WNOHANG ) ) > 0 )
...{
/**//*
* 演示用,不推荐在信号句柄中使用fprintf()
*/
fprintf( stderr, "child <%u> terminated", ( unsigned int )pid );
}
return;
} /**/ /* end of on_sigchld */
... ...
signal( SIGCHLD, on_sigchld );
当然,我们不建议使用signal(),应该使用sigaction()。
原文地址: http://edu.stuccess.com/knowcenter/Unix/16/newcata/00000139.htm