当父母被杀时,Perl是否有一种简单的方法可以杀死子进程?当我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 );
}
Run Code Online (Sandbox Code Playgroud)
注意 使用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
}
Run Code Online (Sandbox Code Playgroud)
当我运行它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
这些过程会被杀死,ps aux | egrep '[s]leep'并在之前和之后进行检查kill.
通过礼貌die的END块被执行有序的,所以你可以清理子进程存在.这样你也可以防止未被捕获die.所以你只使用处理程序来确保END块清理发生.
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 }
Run Code Online (Sandbox Code Playgroud)
这里我们在SIGCHLD处理程序中收集(全部)终止子进程,请参阅perlipc和waitpid中的信号.我们还检查它们是否全部消失(并收获).
由于kill 0, $pid返回true即使孩子是僵尸(退出但没有收获),这可能因为父检查测试发生右后.添加sleep 1后,clean_up_kids()如果需要的话.
一些笔记.这远不是要考虑的完整列表.除了提到的(和其他)Perl文档之外,还可以看到UNIX和C文档,因为Perl的ipc是直接在UNIX系统工具上构建的.
实际上,这里省略了所有错误检查.请加.
等待特定进程是阻塞的,所以如果一些没有被终止,程序将挂起.非阻塞waitpid有另一个警告,请参阅链接的perlipc文档.
在父母被杀之前,子进程可能已经退出.该kill 'TERM'发送SIGTERM但这并不能保证孩子终止.流程可能存在也可能不存在.
信号处理程序可能会在END阶段失效,请参阅此文章.在我的测试中,CHLD仍然在这里处理,但如果这是一个问题,重新安装处理程序,如链接的答案.
有各种方面的模块.例如,请参阅sigtrap pragma.
建议不要在信号处理程序中做很多事情.
有很多事情发生,错误会产生意想不到的后果.
如果你kill是进程组,你将不会遇到任何这些问题,因为所有的孩子也会被终止.在我的系统上,这可以在终端上完成
prompt> kill -s TERM -pid
您可能必须使用数字信号,通常15用于TERM查看man kill您的系统.该-pid代表的进程组,由减号所指.该数字与进程ID相同,但添加say getpgrp;到要查看的代码中.如果shell没有简单地启动这个过程,而是从另一个脚本说,它将属于其父进程组,其子进程也是如此.然后,您需要首先设置自己的进程组,其子进程将继承,然后您可以进入kill 该进程组.请参阅setpgrp和getpgrp,并搜索SO帖子.
| 归档时间: |
|
| 查看次数: |
2411 次 |
| 最近记录: |