ipc perl 杀死后台作业需要杀死两个 pid
Posted
技术标签:
【中文标题】ipc perl 杀死后台作业需要杀死两个 pid【英文标题】:ipc perl killing background job requires killing two pids 【发布时间】:2013-10-22 08:47:20 【问题描述】:这个问题与上一个问题有关: perl run background job and force job to finish?
我以为我有一个可以通过执行kill 15, $logger_pid
成功终止我的后台作业的脚本,但事实证明该命令会创建两个作业。请参阅下面的详细信息:
#!/usr/bin/perl
use strict;
# Do a background $USER top every minute
my $cmd = "top -b -d 1 -n 300 -u $ENVUSER >> logfile";
$SIGCHLD="IGNORE"; my $logger_pid;
unless ($logger_pid=fork) exec($cmd);
# This actually creates two jobs with consecutive PIDs
# $USER 5609 0.0 0.0 63820 1072 pts/9 S 09:42 0:00 sh -c top -b -d 1 -n 300 -u $USER >> logfile
# $USER 5610 0.6 0.0 10860 1216 pts/9 S 09:42 0:00 top -b -d 1 -n 300 -u $USER
# Do something for a while
foreach my $count (1..5) print "$count\n"; sleep 1;
# I thought this first kill command was enough
kill 15, $logger_pid;
# This line is needed to kill the child job
kill 15, ($logger_pid+1);
1;
有人能告诉我为什么我需要第二个kill 15, ($logger-pid+1)
来真正杀死后台工作吗?有没有办法用一个kill
语句来做到这一点?
【问题讨论】:
它们通常是连续的进程 ID,但您不应该依赖它。 @mob,是的,这就是我的恐惧:我宁愿有办法一次性杀死后台进程。 尝试使用负信号kill -15, $logger_pid
(perlmonks.org/?node_id=298613)
我试过kill -15, $logger_pid
,但它并没有杀死这两个进程中的任何一个。
【参考方案1】:
使用sh -c ...
执行带有shell 元字符的外部命令的系统(在您的情况下,>>
用于输出重定向,就此而言,命令字符串中的任何空格)记录在exec
和@987654324 @。为避免使用sh -c
并创建单个进程,可以使用exec
的LIST
形式:
my @cmd = ('top','-b','-d','1','-n','300','-u',$ENVUSER);
exec(@cmd);
输出重定向使这有点棘手,但您可以通过在fork
之后和exec
之前关闭并重新打开STDOUT
来完成它:
my @cmd = ...
close STDOUT;
open STDOUT, '>>', 'logfile';
exec @cmd;
做输出重定向时,重要的是正确设置文件描述符1,不一定STDOUT
。例如,这将无法像您希望的那样进行输出重定向。
my @cmd = ...;
close STDOUT; # close file descriptor 1
open FOO, '>/tmp/asdf'; # probably uses file descriptor 1
open STDOUT, '>>', 'logfile'; # probably uses file descriptor != 1
exec(@cmd); # probably writes output to FOO\/tmp/asdf
使用进程组的替代解决方案: @Chris 在评论中建议您向 kill
函数发送一个负值以杀死整个进程组。通常,您使用fork
创建的进程与其父进程具有相同的进程组,但如果您将子进程设置为使用新的进程组,这将起作用:
unless ($logger_pid = fork)
use POSIX;
POSIX::setpgid($$,$$); # set child process to be in its own process group
exec($cmd);
...
kill -15, $logger_pid; # kill the process group with id $logger_pid
【讨论】:
我将POSIX::setpgid($$,$$)
方法与kill -15, $logger_id
一起使用,现在可以使用了。以上是关于ipc perl 杀死后台作业需要杀死两个 pid的主要内容,如果未能解决你的问题,请参考以下文章