Perl 杀死父对象时杀死子对象
当父进程被终止时,Perl是否有一种简单的方法终止子进程?当我在父PID上运行Perl 杀死父对象时杀死子对象,perl,fork,Perl,Fork,当父进程被终止时,Perl是否有一种简单的方法终止子进程?当我在父PID上运行kill时,子PID将保持活动状态 测试脚本: #!/usr/bin/perl @sleeps = qw( 60 70 80 ); @pids = (); foreach $sleeptime (@sleeps) { my $pid = fork(); if ( not defined $pid ) { die; } elsif ( $pid == 0 ) {
kill
时,子PID将保持活动状态
测试脚本:
#!/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 );
}
这是必须在操作系统上完成的事情,以确保可靠性。Linux有一个
prctl
(进程控制)系统调用,它多路复用许多函数,类似于ioctl
。其中一个函数(操作码PR\u SET\u PDEATHSIG
)安排进程在其父进程死亡时接收特定信号(作为第二个参数传递)
有一个换行prctl
,它作为一个函数显示,该函数接受信号号
如果没有prctl
,子进程(它不是由init进程生成的,因此最初具有除1之外的父进程ID)可以定期测试getppid()的值。如果该值变为1,则表示其原始父代已死亡
管理子进程的进程还可以实现优雅的关闭逻辑:捕获它们的终止信号并作为清理的一部分终止它们的子进程。当然,对于无法处理的信号,这是不可能的。注意第二个例子,使用END
块,更完整。
注意最后讨论了如何使用流程组
大多数情况下,您可能正在处理SIGTERM
信号。为此,您可以通过处理程序安排清理子进程。存在无法捕获的信号,尤其是SIGKILL
和SIGSTOP
。对于那些你将不得不去操作系统,每个答案由。这是给其他人的素描。另请参见下面的其他代码、下面的注释以及最后的流程组使用
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&
的形式运行它时,它会打印出来
[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
这里我们在SIGCHLD
处理程序中获取(所有)终止的子进程,请参阅和。最后我们还要检查它们是否都消失了(并且收获了)
kill 0,$pid
即使子对象是僵尸(已退出但未收获),也会返回true,这可能发生在测试中,因为父对象会在测试后立即进行检查。如果需要,在清理孩子()之后添加sleep 1
一些注释。这是一个需要考虑的事情的清单。除了上面提到的(和其他)Perl文档之外,还可以看到UNIX和C文档,因为Perl的ipc是直接在UNIX系统工具上构建的
- 实际上,这里省略了所有的错误检查。请加上
- 等待特定进程是阻塞的,因此如果某些进程没有终止,程序将挂起。非阻塞
waitpid
还有另一个警告,请参见链接的perlipc
docs
- 子进程可能在父进程被终止之前已退出。
kill'TERM'
发送SIGTERM
,但这并不确保子项终止。过程可能存在,也可能不存在
- 信号处理程序可能在
结束
阶段失效,请参阅。在我的测试中,CHLD
仍然在这里处理,但如果这是一个问题,请重新安装处理程序,如链接的答案所示
- 有一些模块可用于这方面的各个方面。例如,参见pragma
- 最好不要在信号处理程序中做太多工作
- 发生的事情很多,错误可能会产生意想不到的深远后果
如果您kill
进程组,您将不会遇到任何这些问题,因为所有子进程也将被终止。在我的系统上,这可以通过
prompt> kill -s TERM -pid
prompt>kill-s TERM-pid
您可能必须使用数字信号,通常为15
对于术语
,请参阅系统上的杀人
。-pid
代表流程组,由减号表示。该编号与进程ID相同,但添加say getpgrp代码>要查看的代码。如果这个进程不是简单地由shell启动的,而是从另一个脚本启动的,那么它将属于其父进程组,其子进程组也将属于其父进程组。然后您需要首先设置它自己的进程组,它的子进程将继承该进程组,然后您可以kill
该进程组。请参见和。以下内容如何:
kill( -1 * getpgid(), 9 );
(9是SIGKILL:不需要宏。)注意exec(“sleep”,$sleeptime)或die代码>将比系统(“sleep$sleeptime”)简单得多;退出代码>。这会将示例中的进程数从10个减少到4个。听起来您想杀死一个进程组,而不仅仅是一个进程组process@ikegami,我数了7个进程,而不是10个,因为每个fork()+system()加上两个进程(),但这一点很好。@pilcrow,哦,是的,忘记了您提到的优化。请始终整理和缩进您的代码,并在您请求帮助的Perl程序上使用strict
和使用warnings'all
。您正在请求免费帮助,我认为您至少可以让代码可读。这次我是为你做的;请在将来再想想,如果父级在到达该行代码之前死亡,那么调用该调用的是什么?@Kaz一个浮动连字符很容易被忽略。我赞成0-getpgid
kill( -1 * getpgid(), 9 );