如何在不杀死孩子的情况下超时waitpid?

时间:2011-08-30 11:47:12

标签: perl ipc fork waitpid

我知道有关waitpid和超时的许多问题,但他们都通过在警报处理程序中杀死孩子来解决这个问题。

这不是我想要的,我想保持进程运行但是从waitpid发送它。

我尝试解决的底层问题是一个带有处理队列的主循环的守护进程。任务一次处理一次。

如果任务挂起,整个主循环挂起。为了解决这个fork()waitpid似乎是一个明显的选择。如果任务挂起,循环仍然挂起。

我可以想到我根本不使用waitpid的解决方法,但我必须以另一种方式跟踪正在运行的进程,因为我仍然希望一次处理一个任务并且可能挂起任务。

我甚至可以杀死任务,但我想让它运行来检查究竟出了什么问题。还可以转储一些调试信息的kill处理程序。

无论如何,解决这个问题最方便的方法是在可能的情况下超时waitpid。

编辑:

这就是我使用fork()和waitpid的方式,它可能更清楚孩子的意思。

my $pid = fork();

if ($pid == 0){
    # i am the child and i dont want to die
}
elsif ($pid > 0) {
    waitpid $pid, 0;
    # i am the parent and i dont want to wait longer than $timeout
    # for the child to exit
}
else {
    die "Could not fork()";
}

编辑:

使用waitpid WNOHANG做我想要的。这种用法是良好的做法还是你会采取不同的做法?

use strict;
use warnings;
use 5.012;
use POSIX ':sys_wait_h';

my $pid = fork();

if ($pid == 0){
    say "child will sleep";
    sleep 20;
    say "child slept";
}
else {
    my $time = 10;
    my $status;
    do {
        sleep 1;
        $status = waitpid -1, WNOHANG;
        $time--;
    } while ($time && not $status );

    say "bye";
}

3 个答案:

答案 0 :(得分:7)

  

如果任务挂起,整个主循环挂起。绕过这个叉子()   而waitpid似乎是一个明显的选择。如果一个任务挂起循环仍然   挂起。

waitpidWNOHANG选项一起使用。这样它就不会暂停父进程,并且当孩子还没有退出时立即返回0。在你的主循环中,你将不得不定期轮询所有的孩子(任务)。

答案 1 :(得分:3)

而不是定期对所有孩子进行poling,你可能想要设置一个信号处理程序来处理来自perlipc的SIGCHLD:

 use POSIX ":sys_wait_h";
    $SIG{CHLD} = sub {
        while ((my $child = waitpid(-1, WNOHANG)) > 0) {
            $Kid_Status{$child} = $?;
        }
    };
    # do something that forks...

答案 2 :(得分:1)

启用和处理SIGCHLD也是一种可能性;它会在没有轮询的情况下通知您子进程状态更改 - 请参阅手册页中的sigprocmask(2)和signal(3)。