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 并创建单个进程,可以使用execLIST 形式:

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的主要内容,如果未能解决你的问题,请参考以下文章

管道符作业控制变量

Android - 在后台杀死相机进程[重复]

如何使用 php 中的 pid 杀死 linux 进程?

从另一个环境调用 Perl 在后台

如何杀死一个知道pid的进程

系统监控.作业