用叉子结束父进程避免成为僵尸

Posted

技术标签:

【中文标题】用叉子结束父进程避免成为僵尸【英文标题】:End parent process with fork avoiding become zombie 【发布时间】:2013-12-03 12:05:53 【问题描述】:

我正在尝试在 C 项目中实现一些代码,以避免使用阻止我的项目的 pclose。现在我改用fork() + exec(),但我遇到了问题。我创建了一个管道来互连这两个进程。在子进程中,我调用exec() 来执行读取输入的脚本,并在父进程中捕获脚本的输出。

问题是脚本被随机阻止,我不希望这阻止我的程序。当父进程结束读取输出时,它在没有wait() 的情况下完成,以避免无限等待,但因此子进程成为僵尸进程。

这是我的代码:

int    pipefd[2];
        int nbytes = 0;

        signal(SIGCHLD, kill_child);

        pipe(pipefd);
        if (vfork() == 0)
        
                close(pipefd[0]);
                dup2(pipefd[1], 1);
                close(pipefd[1]);
                execl("/bin/sh", "sh", "-c", cpCommand, NULL);
                exit(EXIT_SUCCESS);
        
        else
        
                close(pipefd[1]);
                while ((nbytes = read(pipefd[0], output, sizeof(output))) > 0)
                
                        write(1, output, nbytes);
                
                close(pipefd[1]);
        
        strcpy(cpOutput, output);


void kill_child(int sig_num)

        wait();

解决这个问题的最佳方法是什么?

【问题讨论】:

您的意思是您的read 在父块中调用?然后使管道不堵塞。还是您的意思是 wait 调用阻塞?然后使用例如waitpid 带有 WNOHANG 标志。 所有进程有时会变成僵尸。如果父进程比子进程寿命更长,则子进程将处于僵尸状态,直到进行显式的wait 调用。如果父级终止,而子级仍在运行(孤立),它将被init 进程采用。内核最终会杀死所有子进程(最坏的情况:当你重新启动/关闭系统时),偶尔,init 无论如何都会收割僵尸进程 好的,现在我正在考虑在父进程中使用 waitpid 进行轮询,如果子进程没有完成,则在超时后终止子进程.. 我认为我的 execl 有问题,因为我在它后面放了一个 printf,它从不显示,但脚本结束了.. exec*() 系列函数的成员仅在其参数执行失败的情况下返回,否则它们不返回,因此放在它们之后的任何语句将永远不会执行。详情请见man 3 exec 【参考方案1】:

你可以双叉:

 pid_t pid = fork();
 if (pid == 0) 
      pid = fork();
      if (pid == 0) 
           ...
           execl(...);
      
      _exit(0);
 

 waitpid(pid, ...);

 read(...);

也许,setsid() 应该在子进程中调用和/或 SIGHUP 被忽略。

上面的代码将第二个孩子(你的execl())从主程序中分离出来,init 将获得它。

您可能希望使用一些控制管道向主进程发出错误信号(execl() 失败)。

【讨论】:

@downvoters:如果你能证明你的行为是正当的,那就太好了

以上是关于用叉子结束父进程避免成为僵尸的主要内容,如果未能解决你的问题,请参考以下文章

PHP僵尸进程

PHP僵尸进程

PHP 中的僵尸进程孤儿进程详解

孤儿进程和僵尸进程

孤儿进程和僵尸进程

【linux c】子进程结束了,父进程还在,用ps -ef查看,子进程变成僵尸进程了。