用叉子结束父进程避免成为僵尸
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:如果你能证明你的行为是正当的,那就太好了以上是关于用叉子结束父进程避免成为僵尸的主要内容,如果未能解决你的问题,请参考以下文章