如何在不杀死子进程的情况下超时等待waitpid?

4
我知道有很多关于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个回答

7
如果一个任务挂起,整个主循环都会挂起。为了解决这个问题,fork()和waitpid似乎是一个明显的选择。但是,如果一个任务挂起,循环仍然会挂起。
使用waitpid以WNOHANG选项。这样它不会挂起父进程,并且当子进程尚未退出时,它会立即返回0。在主循环中,您需要定期轮询所有子进程(任务)。

5

与其定期轮询所有子进程,您可能希望设置一个信号处理程序来处理 SIGCHLD 信号... 参见 perlipc:

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

1

启用和处理SIGCHLD也是一种可能性;它将通知您子进程状态的更改,而无需轮询 - 请参阅手册页中的sigprocmask(2)和signal(3)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接