这是我的代码,为了清楚起见,删除了错误处理和其他内容:
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); } } }
launch子程序执行一个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 $!; } }
monitor sub基本上只等待一段指定的时间,然后尝试终止shell脚本.
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; } }
这会杀死脚本,但是它不会杀死任何子进程.怎么修?
解决方法
如果操作系统支持,则可以使用进程组执行此操作.您需要使脚本流程成为流程组负责人.它运行的子进程将从其父进程继承进程组.然后,您可以使用kill同时向组中的每个进程发送信号.
在launch()中,您需要将打开的行替换为fork.然后在子进程中,在执行命令之前调用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;