4

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

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

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

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

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

我什至可以终止任务,但我想让它运行以检查到底出了什么问题。转储一些调试信息的终止处理程序也是可能的。

无论如何,解决该问题的最方便的方法是在可能的情况下使 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";
}
4

3 回答 3

7

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

waitpidWNOHANG选项一起使用。这样它就不会暂停父进程,并且会0在子进程尚未退出时立即返回。在您的主循环中,您必须定期轮询所有子项(任务)。

于 2011-08-30T11:51:51.047 回答
5

您可能希望设置一个信号处理程序来处理来自 perlipc 的 SIGCHLD ...,而不是定期对所有子节点进行轮询:

 use POSIX ":sys_wait_h";
    $SIG{CHLD} = sub {
        while ((my $child = waitpid(-1, WNOHANG)) > 0) {
            $Kid_Status{$child} = $?;
        }
    };
    # do something that forks...
于 2013-10-16T20:39:00.920 回答
1

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

于 2013-01-25T22:04:17.640 回答