Perl fork和kill-kill(0,$pid)总是返回1,并且可以';不要杀了这个孩子

Perl fork和kill-kill(0,$pid)总是返回1,并且可以';不要杀了这个孩子,perl,Perl,我正在Linux主机上运行一个perl脚本。我试图写一个分叉的脚本,在这个脚本中,孩子启动一个程序,花费很长时间,而家长在5秒钟后超时,杀死了孩子。以下是我所拥有的: my $start = time(); my $timeOut = 5; my $childPid = fork(); if ($childPid) { # I am the parent, and $childPid is my child while (kill(0, $childPid)) {

我正在Linux主机上运行一个perl脚本。我试图写一个分叉的脚本,在这个脚本中,孩子启动一个程序,花费很长时间,而家长在5秒钟后超时,杀死了孩子。以下是我所拥有的:

my $start = time();
my $timeOut = 5;

my $childPid = fork();
if ($childPid) {
    # I am the parent, and $childPid is my child
    while (kill(0, $childPid)) {
        if (time() > $start + $timeOut) {
            $numKilled = kill(SIGTERM, $childPid);
            printf("numKilled: %s\n", $numKilled);
        }
        sleep 1;
    }
}
else {
    # I am the child - do something that blocks forever
    `adb -s 410bf6c1 logcat`;
    exit;
}
输出:

aschirma@graphics9-lnx:~$ perl perl-fork-test.pl 
numKilled: 1
numKilled: 1
numKilled: 1
numKilled: 1
numKilled: 1
...
我期望的行为是,我只看到“numKilled:1”一次,子进程(及其任何子进程)在大约5秒后被杀死。但我从实验中看到,无论是孩子还是孩子都不会被杀。
kill(SIGTERM$childPid)
似乎什么也不做


我怎样才能真正杀死这个孩子呢?

很可能你在脚本中既不使用
严格的
也不使用
POSIX
,因此
SIGTERM
被解释为赤裸裸的
“SIGTERM”
,这是没有用的


使用strict
将这个意外的裸字变成一个错误,然后
使用POSIX
拉入
SIGTERM
常量。

我也看到了这种行为,kill 0即使在进程结束后也返回true;我怀疑您可能丢失了对waitpid的调用(通常在SIGCHLD处理程序中完成),这将导致这种情况,但即使在添加它之后,kill 0仍会继续返回true

我建议您使用非阻塞waitpid而不是kill(并验证该进程是否确实在SIGTERM信号下死亡-有些可能不会,至少不会立即死亡)。如果SIGTERM不起作用,您可能还想在一段时间后尝试SIGINT,最后使用SIGKILL。

来自:

如果你不伺候孩子就用叉子叉,你会积攒的 僵尸。在某些系统上,可以通过将$SIG{CHLD}设置为 “忽略”

当添加
$SIG{CHLD}='IGNORE'时,我能够获得所需的行为到代码的顶部

[ben@imac ~]$ perl test.pl
numKilled: 1
[ben@imac ~]$ 

或者,添加
waitpid($childPid,0)kill
之后,code>也起到了作用。

应该是这样的。这不是遵循最佳实践,但它应该可以帮助您解决问题

#!/usr/bin/perl

use warnings;
use strict;
use POSIX qw(:sys_wait_h);

my $timeOut = 5;
$SIG{ALRM} = \&timeout;
$SIG{CHLD} = 'IGNORE',
alarm($timeOut);

my $childPid = fork();
if ($childPid) {
    while(1) {
        print "[$$]: parent...\n"; 
        sleep(2); 
    }
}else {
    # I am the child - do something that blocks forever
    while(1){
        print "[$$]: child...\n";
        sleep(2);
    }
    exit;
}

sub timeout {
    print "killing $childPid\n";
    print "###\n" . `ps -ef | grep -v grep | grep perl` . "###\n";
    if ( ! (waitpid($childPid, WNOHANG)) ) {
        print "killing $childPid...\n";
        kill 9, $childPid;
        die "[$$]: exiting\n";
    }
}
输出:

$ forktest.pl
[24118]: parent...
[24119]: child...
[24118]: parent...
[24119]: child...
[24118]: parent...
[24119]: child...
killing 24119
###
cblack   24118 12548  0 14:12 pts/8    00:00:00 /usr/bin/perl ./forktest.pl
cblack   24119 24118  0 14:12 pts/8    00:00:00 /usr/bin/perl ./forktest.pl
###
killing 24119...
[24118]: exiting

尝试终止进程组(使用-$pid):


请参阅perlipc.

我认为问题在于作为'kill'的第一个参数传递的'0'。当我阅读文档时,他们说“0”只会检查是否可以向进程发送信号,而不发送信号。在您的情况下,您希望向子进程发送“KILL”信号,因此请执行以下操作:

kill( 'KILL', $childPid );

是否从某处导入
SIGTERM
常量?我打赌它的计算结果为0。您是否使用
使用警告;严格使用?为什么不呢?嘿,伙计们,所以我发现我看到的问题其实有点不同-kill是杀死子进程,但不是它的任何子进程。我不想仅仅编辑整个问题,我应该开始一个新的问题吗?稍微偏离主题,但是在检查您的子进程句柄之前,考虑检查<代码>(定义($AddiPID))< /代码>。code>fork
如果无法创建进程,则返回
undef
。或者只执行
kill'TERM'、$pid
,不必处理常量。请参阅:“您也可以在引号中使用信号名。”我按照您的建议执行了所有操作,但行为是相同的。kill(0,$childPid)仍然不断地显示进程存在,我可以手动确认它确实存在。kill(0,$childPid)基本上是说如果进程正在运行,那么继续。。随后,他将发送一份SIGTERM
kill( 'KILL', $childPid );