在Perl中,杀害儿童和它的孩子孩子使用开放创建时
这里是我的代码,错误处理和其他的东西为清楚起见移除:在Perl中,杀害儿童和它的孩子孩子使用开放创建时
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);
}
}
}
推出子执行shell脚本,启动其他过程,像这样:
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 $!;
}
}
监视器子基本上只是等待指定的时间周期,然后尝试杀外壳脚本。
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;
}
}
这会杀死脚本,但是它不会杀死它的任何子进程。怎么修?
你可以用进程组做到这一点,如果您的操作系统支持他们。你需要使脚本程序成为进程组创建者。子进程,这将运行从其父继承进程组。然后,可以使用杀来的信号在同一时间发送到每个进程在一组。
在launch()
中,您需要将open
行替换为分叉。然后在孩子,你会exec'ing命令之前调用setpgrp()
。像下面这样的东西应该工作:
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:
kill 9, -$pid;
我认为你应该否定信号编号(或名称)而不是PID:'kill'-9',$ pid'。 – jreisinger 2015-08-26 12:09:08
尝试增加:
use POSIX qw(setsid);
setsid;
你launch_and_monitor
函数的顶部。这将使你的流程在一个单独的会话,并导致东西离开时,会议领导(即主)退出。
杀灭processgroup作品,但不要” t忘记父母也可以单独被杀害。假设子进程有一个事件循环,他们可以在执行fork()以验证有效性之前检查在套接字对中创建的父套接字。事实上,当父套接字不存在时,select()干净地退出,所有需要做的就是检查套接字。
E.g.:
use strict; use warnings;
use Socket;
$SIG{CHLD} = sub {};
socketpair(my $p, my $c, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die $!;
print "parent $$, fork 2 kids\n";
for (0..1){
my $kid = fork();
unless($kid){
child_loop($p, $c);
exit;
}
print "parent $$, forked kid $kid\n";
}
print "parent $$, waiting 5s\n";
sleep 5;
print "parent $$ exit, closing sockets\n";
sub child_loop {
my ($p_s, $c_s) = @_;
print "kid: $$\n";
close($c_s);
my $rin = '';
vec($rin, fileno($p_s), 1) = 1;
while(1){
select my $rout = $rin, undef, undef, undef;
if(vec($rout, fileno($p_s), 1)){
print "kid: $$, parent gone, exiting\n";
last;
}
}
}
运行像这样:
[email protected]:~$ perl ~/abc.pl
parent 5638, fork 2 kids
parent 5638, forked kid 5639
kid: 5639
parent 5638, forked kid 5640
parent 5638, waiting 5s
kid: 5640
parent 5638 exit, closing sockets
kid: 5640, parent gone, exiting
kid: 5639, parent gone, exiting
[email protected]:~$
我没有回答你的主要问题,但我会建议做'REAPER'匿名子,例如'我的$ reaper = sub {...}; $ SIG {CHLD} = $ reaper;'将一个名为sub的子文件放入另一个子文件夹中并不会将其隐藏在其他作用域中。所有指定的subs都是Perl中的包号符号 – friedo 2009-11-04 18:39:39
http://www.speculation.org/garrick/kill-9.html – 2009-11-04 19:21:18
好点,谢谢指出 – richard 2009-11-04 19:36:16