This question already has answers here:
In perl, killing child and its children when child was created using open
(4个答案)
4年前关闭。
当父级被杀死时,Perl是否有一种简单的方法来杀死子进程?当我在父PID上运行
测试脚本:
当我将其作为
在这里,我们在
即使孩子是僵尸(已退出但未收割),
一些注意事项。这远远不是要考虑的完整事情清单。由于Perl的ipc是直接在UNIX系统工具上构建的,因此与提到的Perl文档一起(以及其他),Perl文档也可以看到UNIX和C文档。
实际上,这里省略了所有错误检查。请添加 等待特定进程被阻止,因此如果某些进程没有终止,则程序将挂起。非阻塞 在父进程被杀死之前,子进程可能已经退出。 信号处理程序可能会在 有用于此方面各个方面的模块。参见sigtrap pragma,例如 建议不要在信号处理程序中做太多事情 发生了很多事情,错误可能会带来意想不到且范围广泛的后果
如果您用
提示> kill -s TERM -pid
您可能必须使用数字信号,通常将
(4个答案)
4年前关闭。
当父级被杀死时,Perl是否有一种简单的方法来杀死子进程?当我在父PID上运行
kill
时,孩子仍然活着。测试脚本:
#!/usr/bin/perl
@sleeps = qw( 60 70 80 );
@pids = ();
foreach $sleeptime (@sleeps) {
my $pid = fork();
if ( not defined $pid ) {
die;
}
elsif ( $pid == 0 ) {
#child
system("sleep $sleeptime");
exit;
}
else {
#parent
push @pids, $pid;
}
}
foreach $pid (@pids) {
waitpid( $pid, 0 );
}
最佳答案
注意。第二个示例使用END
块,它更加完整。
注意结束了有关如何为此使用进程组的讨论。
大多数情况下,您正在处理SIGTERM
信号。为此,您可以安排通过处理程序清理子进程。存在无法捕获的信号,尤其是SIGKILL
和SIGSTOP
。对于那些您必须转到操作系统的系统,请按照Kaz的答案进行操作。这是给别人的草图。另请参见其下的其他代码,其下的注释以及最后的流程组使用。
use warnings;
use strict;
use feature qw(say);
say "Parent pid: $$";
$SIG{TERM} = \&handle_signal; # Same for others that can (and should) be handled
END { say "In END block ..." }
my @kids;
for (1..4) {
push @kids, fork;
if ($kids[-1] == 0) { exec 'sleep 20' }
}
say "Started processes: @kids";
sleep 30;
sub handle_signal {
my $signame = shift;
say "Got $signame. Clean up child processes.";
clean_up_kids(@kids);
die "Die-ing for $signame signal";
};
sub clean_up_kids {
say "\tSending TERM to processes @_";
my $cnt = kill 'TERM', @_;
say "\tNumber of processes signaled: $cnt";
waitpid $_, 0 for @_; # blocking
}
当我将其作为
signals.pl &
运行然后kill运行时,它会打印[13] 4974 Parent pid: 4974 Started processes: 4978 4979 4980 4982 prompt> kill 4974 Got TERM. Clean up child processes. Sending TERM to processes 4978 4979 4980 4982 Number of processes signaled: 4 Die-ing for TERM signal at signals.pl line 25. In END block ... [13] Exit 4 signals.pl
The processes do get killed, checked by ps aux | egrep '[s]leep'
before and after kill
.
By courtesy of die
the END
block gets executed orderly so you can clean up child processes there. That way you are also protected against uncaught die
. So you'd use the handler merely to ensure that the END
block cleanup happens.
use POSIX "sys_wait_h";
$SIG{CHLD} = sub { while (waitpid(-1, WNOHANG) > 0) { } }; # non-blocking
$SIG{TERM} = \&handle_signal;
END {
clean_up_kids(@kids);
my @live = grep { kill 0, $_ } @kids;
warn "Processes @live still running" if @live;
}
sub clean_up_kids {
my $cnt = kill 'TERM', @_;
say "Signaled $cnt processes.";
}
sub handle_signal { die "Die-ing for " . shift }
在这里,我们在
SIGCHLD
处理程序中收获(全部)终止的子进程,请参阅Signals in perlipc和waitpid。最后,我们还将检查它们是否全部消失(并收割)。即使孩子是僵尸(已退出但未收割),
kill 0, $pid
也会返回true,这可能会在测试中发生,因为父级会立即检查。如果需要,在sleep 1
之后添加clean_up_kids()
。一些注意事项。这远远不是要考虑的完整事情清单。由于Perl的ipc是直接在UNIX系统工具上构建的,因此与提到的Perl文档一起(以及其他),Perl文档也可以看到UNIX和C文档。
waitpid
有另一个警告,请参阅链接的perlipc
文档kill 'TERM'
发送SIGTERM
,但这不能确保子项终止。进程可能存在或可能不存在END
阶段失效,请参阅this post。在我的测试中,仍然在此处处理CHLD
,但是如果这有问题,请重新安装处理程序,如链接的答案如果您用
kill
进程组,那么您将不会遇到任何这些问题,因为所有子进程也会被终止。在我的系统上,这可以在终端上通过提示> kill -s TERM -pid
您可能必须使用数字信号,通常将
15
用作TERM
,请参见系统上的man kill
。 -pid
代表过程组,由减号表示。该数字与进程ID相同,但是将say getpgrp;
添加到要查看的代码中。如果不是仅由 shell 程序启动该进程,而是从另一个脚本启动,则它将属于其父进程组,其子进程也将属于该进程组。然后,您需要首先设置自己的进程组,其子进程将继承该进程组,然后可以对该进程组进行kill
。参见setpgrp和getpgrp。关于perl - parent 被杀时杀死 child ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38236478/
10-15 10:38