【问题标题】:Linux, waitpid, WNOHANG, child process, zombieLinux、waitpid、WNOHANG、子进程、僵尸
【发布时间】:2014-05-09 03:02:44
【问题描述】:

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

父进程只等待子进程,当它意外死亡时,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

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

【问题讨论】:

    标签: linux process kill zombie-process waitpid


    【解决方案1】:

    你可以简单地使用

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

    不要睡一会儿再试一次。

    【讨论】:

    • 这个过程实际上一直在做有用的工作。该进程保存了对慢速文件系统上的大文件的最后引用。当进程终止时,对文件的最后引用是释放,强制操作系统回收空间。文件太大,需要数万次 I/O 操作,耗时 10 分钟或更长时间
    • @Cube 可能你观察到的类似现象是由类似的原因引起的,即当你通过ps发现子进程处于僵尸状态时,子进程实际上并没有完成退出然而,内核可能在那个时候代表那个子进程做一些有用的工作,比如刷新文件系统。
    • @leeduherm 你知道有什么办法可以处理这种“有用的工作”吗,也许我可以在向子进程发送退出信号之前完成工作,子进程应该立即退出而不是变成僵尸一段时间的状态。
    • @Cube 你看到你提供的问题链接得到了回答吗?如果你在堆栈的其他地方发现了同样的问题,那么用更多的细节再次重复这个问题是不好的。您在 3 月 31 日提出的问题作为一个单独的问题可能会更好。您可能会感兴趣的是专门研究更好的资源分配和进程排序以避免不同的僵尸出现情况,提供一个更加抽象的示例。 :)
    【解决方案2】:

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

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

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

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

    【讨论】:

    • 众所周知,当进程退出时,操作系统会回收所有分配的资源:@​​987654324@分配的内存,open分配的文件名指定,socket分配的域指定.文件名指定回收将包含大量OS IO,如果文件很大,将完成大量OS IO,并且在执行过程中必须将进程变成僵尸。 lsof 命令将显示所有已打开的文件。我终于发现我打开后忘记关闭fd,所以很多泄漏fds都是问题。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2012-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-12
      • 2016-07-03
      相关资源
      最近更新 更多