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)
似乎无能为力。我怎样才能真正杀死孩子?
#1 楼
在perldoc分支中:如果您不等待孩子就进行分支,则会堆积僵尸。在某些系统上,可以通过将$ SIG {CHLD}设置为
“ IGNORE”来避免这种情况。
将
$SIG{CHLD} = 'IGNORE';
添加到顶部时,我能够获得所需的行为。的代码。[ben@imac ~]$ perl test.pl
numKilled: 1
[ben@imac ~]$
或者,在
waitpid($childPid, 0);
之后添加kill
也可以解决问题。#2 楼
应该是这样的。这不是遵循最佳做法,但它应该可以帮助您解决问题...#!/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";
}
}
输出: >
#3 楼
可能是因为您在脚本中既没有use
也没有strict
或POSIX
,所以SIGTERM
被解释为裸字"SIGTERM"
,它的行为方式并不有用。错误,然后use strict
提取use POSIX
常数。评论
或者只是杀死'TERM',$ pid而不用担心常数。
–melpomene
13年2月21日在21:29
请参阅perldoc.perl.org/functions/kill.html:“您也可以在引号中使用信号名称。”
–melpomene
13年2月21日在21:39
我做了您建议的所有操作,但是行为是相同的。 kill(0,$ childPid)仍然不断显示该进程存在,我可以手动确认它确实存在。
–亚当S
13年2月21日在21:49
#4 楼
我也看到了这种行为,即使进程消失了,kill 0也返回true。我怀疑您可能会丢失对waitpid的调用(通常在SIGCHLD处理程序中完成),这将导致此情况,但是即使添加了它,kill 0仍会返回true。我建议您使用非阻塞waitpid而不是kill(并验证该进程确实确实在SIGTERM信号上死亡-有些可能不会,至少立即消失)。如果SIGTERM无法正常工作,您可能还需要一段时间后再尝试SIGINT,而在最后一种情况下,SIGKILL。
#5 楼
尝试杀死进程组(使用-$ pid):kill TERM => -$pid;
请参见perlipc。
#6 楼
我认为问题出在作为“ kill”的第一个参数传递的“ 0”。当我阅读文档时,他们说'0'只会检查您是否可以将信号发送到进程,而不发送信号。对于您的情况,您想将'KILL'信号发送给子进程,因此请执行以下操作:kill( 'KILL', $childPid );
评论
kill(0,$ childPid)基本上是说该进程是否正在运行,然后继续..随后他正在发送SIGTERM
– PodTech.io
17年7月26日在12:40
评论
您是从某个地方导入SIGTERM常量吗?我敢打赌它的值为0。您是否正在使用使用警告?使用严格;?为什么不呢?
大家好,所以我发现我看到的问题实际上有所不同-kill是杀死子进程,但不是杀死它的任何子进程。我不想只编辑整个问题,我应该开始一个新的问题吗?
稍微偏离主题,但在对子进程句柄执行任何操作之前,请考虑检查是否(define($ childPid))。 fork会在无法创建进程的情况下返回undefif。