5

我将我的程序作为守护进程运行。

父进程只等待子进程,当它意外死亡时,fork 并再次等待。

for (; 1;) {
  if (fork() == 0) break;
  int sig = 0;
  for (; 1; usleep(10000)) {
    pid_t wpid = waitpid(g->pid[1], &sig, WNOHANG);
    if (wpid > 0) break;
    if (wpid < 0) print("wait error: %s\n", strerror(errno));
  }
}

但是当子进程被 -9 信号杀死时,子进程进入僵尸进程。

waitpid应该立即返回子进程的pid!
但是waitpid大约90秒后得到了pid号,

cube     28139  0.0  0.0  70576   900 ?        Ss   04:24   0:07 ./daemon -d
cube     28140  9.3  0.0      0     0 ?        Zl   04:24 106:19 [daemon] <defunct>

这是父亲的踪迹

父亲没有卡住,总是调用wait4。

strace -p 28139
Process 28139 attached - interrupt to quit
restart_syscall(<... resuming interrupted call ...>) = 0
wait4(28140, 0x7fff08a2681c, WNOHANG, NULL) = 0
nanosleep({0, 10000000}, NULL)          = 0
wait4(28140, 0x7fff08a2681c, WNOHANG, NULL) = 0

大约 90 秒后,父亲得到了 SIGCHILD,wait4 返回了死去孩子的 pid。

--- SIGCHLD (Child exited) @ 0 (0) ---
restart_syscall(<... resuming interrupted call ...>) = 0
wait4(28140, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGKILL}], WNOHANG, NULL) = 28140

为什么子进程没有立即退出?反而意外地变成了丧尸。

4

3 回答 3

3

我终于发现在 lsof 的深度跟踪过程中存在一些 fd 泄漏。

修复 fd 泄漏后,问题就消失了。

于 2014-04-30T15:45:48.947 回答
1

在我看来,waitpid 没有立即返回子 pid,只是因为该进程不可用。

此外,看起来您实际上希望您的代码执行此操作,因为您使用选项指定waitpid()NOHANG它可以防止阻塞,如果子 pid 不可用,基本上允许父级继续前进。

也许你的过程使用了你没想到的东西?你能追踪它的活动,看看你是否找到了瓶颈吗?

这是一个非常有用的链接,可能会对您有所帮助:http: //infohost.nmt.edu/~eweiss/222_book/222_book/0201433079/ch08lev1sec6.html

于 2014-04-29T21:13:54.897 回答
1

你可以简单地使用

  for (;;) {
    pid_t wpid = waitpid(-1, &sig, 0);
    if (wpid > 0) break;
    if (wpid < 0) print("wait error: %s\n", strerror(errno));
  }

而不是睡一会儿再试一次。

于 2014-03-29T18:20:22.457 回答