我在RedHat Linux中编写了一个简单的C程序,在调用execv后等待使用waitpid的子进程。
int main( int argc, char * argv[] )
{
int pid;
int status = 0;
int wait_ret;
const char * process_path = argv[1];
if ( argc < 2 )
{
exit( EXIT_FAILURE );
}
pid = fork(); //spawn child process
if ( 0 == pid ) //child
{
int ret = execv( process_path, &argv[1] );
if ( ret )
{
printf( "execv failed: %s\n", strerror( errno ) );
}
exit( EXIT_SUCCESS );
}
//wait for the child to terminate
wait_ret = waitpid( pid, &status, WUNTRACED );
if ( -1 == wait_ret )
{
printf( "ERROR: Failed to wait for process termination\n" );
exit( EXIT_FAILURE );
}
// ... handlers for child exit status ...
return 0;
}
我正在使用它作为我正在运行的某些进程的简单监视器。
我的问题是,一个进程特别是在退出时没有被waitpid收获,而是在waitpid挂起时永远保持在Zombie状态。我不确定为什么waitpid一旦变成僵尸(可能是泄露的文件描述符或其他东西)就无法收获这个过程。
我可以使用WNOHANG标志并轮询孩子的stat proc文件以检查Zombie状态,但我更喜欢更优雅的解决方案。也许有一些函数我可以使用它来获取Zombie状态而不轮询这个文件?
有没有人知道waitpid的替代方案,当进程变为Zombie时会返回?
其他信息:
通过在其中一个主题中调用exit( EXIT_FAILURE);
来关闭子进程。
cat /proc/<CHILD_PID>/stat
(退出前):
1037(my_program)S 1035 58 58 0 -1 4194560 1309 0 22 0 445 1749 0 0 20 0 13 0 4399 22347776 1136 4294967295 3336716288 3338455332 3472776112 3472775232 3335760920 0 0 4 31850 4294967295 0 0 17 0 0 0 26 0 0 3338489412 3338507560 3338600448
cat /proc/<CHILD_PID>/stat
(退出后):
1037(my_program)Z 1035 58 58 0 -1 4227340 1316 0 22 0 464 1834 0 0 20 0 2 0 4399 0 0 4294967295 0 0 0 0 0 0 0 4 31850 4294967295 0 0 17 0 0 0 26 0 0 0 0 0
请注意,在这种情况下,子PID为1037,父PID为1035。
答案 0 :(得分:0)
我的问题是,一个进程特别是在退出时没有被waitpid收获,而是在waitpid被挂起时永远处于Zombie状态?如果我理解正确,你不需要孩子成为僵尸然后使用SA_NOCLDWAIT
标志。来自sigaction()
SA_NOCLDWAIT(自Linux 2.6起) 如果signum是SIGCHLD,请不要将孩子变成僵尸 当他们终止。另见waitpid(2)。这个标志是 只有在为SIGCHLD建立处理程序时才有意义,或者 将信号的处置设置为SIG_DFL时。
If the SA_NOCLDWAIT flag is set when establishing a handler for SIGCHLD, POSIX.1 leaves it unspecified whether a SIGCHLD signal is generated when a child process terminates. On Linux, a SIGCHLD signal is generated in this case; on some other implementations, it is not.
想法是当子进程首先完成,父进程收到17号信号或SIGCHLD
&amp;当父母仍在运行时,子进程将变为僵尸。所以如何尽快删除子,它变成僵尸,解决方案是使用标志SA_NOCLDWAIT
。
以下是示例代码
void my_isr(int n) {
/* error handling */
}
int main(void) {
if(fork()==0) { /* child process */
printf("In child process ..c_pid: %d and p_pid : %d\n",getpid(),getppid());
sleep(5);
printf("sleep over .. now exiting \n");
}
else { /*parent process */
struct sigaction v;
v.sa_handler=my_isr;/* SET THE HANDLER TO ISR */
v.sa_flags=SA_NOCLDWAIT; /* it will not let child to become zombie */
sigemptyset(&v.sa_mask);
sigaction(17,&v,NULL);/* when parent receives SIGCHLD, IT GETS CALLED */
while(1); /*for observation purpose, to make parent process alive */
}
return 0;
}
只需评论/取消注释v.sa_flags=SA_NOCLDWAIT;
行&amp;通过在一个终端中运行a.out来分析行为。检查另一个终端中的ps -el | grep pts/0
。
有没有人知道waitpid的替代方法,当进程变为僵尸时会返回?使用WNOHANG
就像你做的那样&amp;在waitpid()
如果孩子已经停止(但没有追踪),WUNTRACED也会返回 通过 ptrace的(2))。已经停止的被追踪儿童的状况 即使未指定此选项,也会提供。
答案 1 :(得分:0)
任何终止的进程都会变成僵尸进程,直到它被 wait
调用回收。在这里等待似乎并非在所有情况下都会发生。
从给出的代码中,我无法弄清楚为什么等待没有发生并且进程仍然是僵尸。 (无论如何也不能不运行它)
但不是只等待特定的 pid
,您可以通过使用 -1 作为 waitpid
的第一个参数来等待 任何 子项。不要使用 WNOHANG
,因为它需要忙轮询(不要这样做)。
您可能还想删除 WUNTRACED
,除非您有特定的理由要包含它。但是丢掉它并看看它有什么不同没有坏处。