在perl中,使用open创建child时会杀死child及其子 [英] In perl, killing child and its children when child was created using open

查看:89
本文介绍了在perl中,使用open创建child时会杀死child及其子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的代码,为清楚起见删除了错误处理和其他内容:

Here's my code, with error handling and other stuff removed for clarity:

sub launch_and_monitor {  

    my ($script, $timeout) = @_;

    sub REAPER {
        while ((my $child = waitpid(-1, &WNOHANG)) > 0) {}
        $SIG{CHLD} = \&REAPER;
    }
    $SIG{CHLD} = \&REAPER;

    my $pid = fork;
    if (defined $pid) {
        if ($pid == 0) {
            # in child
            monitor($timeout);
        }
        else {
            launch($script);
        }
    }
}

launch子执行一个shell脚本,该脚本随后又启动其他进程,例如:

The launch sub executes a shell script which in turn launches other processes, like so:

sub launch($) {

    my ($script) = @_;

    my $pid = open(PIPE, "$script|");

    # write pid to pidfile

    if ($pid != 0) {
        while(<PIPE>) {
            # do stuff with output
        }
        close(PIPE) or die $!;
    }
}

Monitor子程序基本上只是等待指定的时间,然后尝试杀死Shell脚本.

The monitor sub basically just waits for a specified period of time and then attempts to kill the shell script.

sub monitor($) {

    my ($timeout) = @_;

    sleep $timeout;

    # check if script is still running and if so get pid from pidfile
    if (...) {
        my $pid = getpid(...);        
        kill 9, $pid;
    }
}

这会杀死脚本,但是不会杀死它的任何子进程.如何解决?

This kills the script, however, it does not kill any of it's sub processes. How to fix?

推荐答案

如果操作系统支持进程组,则可以执行此操作.您需要使脚本流程成为流程组负责人.它运行的子进程将从其父进程继承该进程组.然后,您可以使用kill将信号同时发送到组中的每个进程.

You can do this with process groups, if your operating system supports them. You need to make the script process become a process group leader. The child processes that it runs will inherit the process group from their parent. You can then use kill to send a signal to each process in the group at the same time.

launch()中,您需要将open行替换为分叉的行.然后在子级中,您将在执行命令之前调用setpgrp().像下面这样的东西应该起作用:

In launch(), you will need to replace the open line with one that forks. Then in the child, you would call setpgrp() before exec'ing the command. Something like the following should work:

my $pid = open(PIPE, "-|");
if (0 == $pid) {
    setpgrp(0, 0);
    exec $script;
    die "exec failed: $!\n";
}
else {
    while(<PIPE>) {
        # do stuff with output
    }
    close(PIPE) or die $!;
}

稍后,要杀死脚本进程及其子进程,请取消您要发信号通知的进程ID:

Later, to kill the script process and its children, negate the process ID that you're signalling:

kill 9, -$pid;

这篇关于在perl中,使用open创建child时会杀死child及其子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆