在运行进程时如何等待运行进程在perl中完成不是子进程?

时间:2016-05-17 06:51:25

标签: perl waitpid

我正在使用正在使用的Perl脚本 waitpid($pid, 0)等待当前进程完成。 但是在此print之后写的waitpid语句在进程完成之前打印它。

我想知道为什么waitpid没有等待首先完成流程。

此外,对运行进程的控制在不同的模块下,而不是这个perl脚本的一部分。只有可访问的是进程的pid和名称。我无法更改调用该过程的模块中的任何内容。

2 个答案:

答案 0 :(得分:3)

waitpid documentation州:

  

等待特定的子进程终止并返回pid   死亡过程中的,如果没有这样的子过程,则为-1。

快速测试:

my $pid = open my $fh,"-|","sleep 3";
print waitpid(28779,0); # Some other process
print waitpid($pid,0);

28779是当前正在运行的另一个进程(从ps axu中随机获取)。输出:

-1
4088

您无法使用waitpid等待与您当前流程不同的流程。

The kill command可以检查PID当前是否正在运行:

print kill(0,28779);

输出:

1

你仍然需要轮询(使用sleep循环)让pid消失。还要记住,受监视的进程可能会退出,并且新进程可能会在您下次检查之前重用相同的PID(不太可能,但可能)。

答案 1 :(得分:2)

注意评论时,一个带有kill 0, $pid的简单的单行内容即将结束。

我们需要检测外部程序的完成情况,该程序尚未由此脚本启动。该问题询问使用waitpid。要复制我的早期评论:

  

你做不到。您只能等待子进程。请参阅perldoc wait(或waitpid,它是相同的),第一句话。

waitwaitpid等待传递给脚本的关于其子(f)的命运的信号。脚本没有理由接收有关它没有启动的进程的信号。

我们知道进程的id和名称。其PID可用于轮询以确定它是否正在运行。单独使用pid并不完全可靠,因为在我们的检查之间,流程可以完成,随机的新流程可以分配相同的pid。我们可以使用该程序的名称来加强这一点。

在Linux系统上,可以使用(许多ps选项获取有关进程的信息。其中任何一个都返回程序的完全调用

ps --no-headers -o cmd PID
ps --no-headers -p PID -o cmd

返回的字符串可以从解释器的路径开始(例如,对于Perl脚本),然后是程序的全名。版本ps -p PID -o comm=仅返回程序的名称,但我发现它可能会在连字符(如果有)上破坏该单词,从而导致名称不完整。这可能需要在某些系统上进行调整,请咨询您的man ps。如果没有给定PID的进程,我们什么也得不回。

然后我们可以检查PID,如果找到则检查该PID的名称是否与程序匹配。该程序的名称是已知的,我们可以硬编码。但是,在脚本启动时仍然可以使用上面的ps命令获取它,以避免歧义。 (然后它也采用相同的格式供以后比较。)这​​个本身是根据已知名称进行检查的,因为不能保证脚本执行时的PID确实适用于预期的程序。

use warnings;
use strict;

# For testing. Retrieve your PID as appropriate for real use    
my $ext_pid = $ARGV[0] || $$;

my $cmd_get_name = "ps --no-headers -o cmd $ext_pid";

# For testing.  Replace 'sleep' by your program name for real use
my $known_prog_name = 'sleep';

# Get the name of the program with PID
my $prog_name = qx($cmd_get_name);

# Test against the known name, exit if there is a mismatch
if ($prog_name !~ $known_prog_name) {
    warn "Mismatch between:\n$prog_name\n$known_prog_name -- $!";
    exit;
}   

my $name;
while ( $name = qx($cmd_get_name) and $name =~ /$prog_name/ )
{
    print "Sleeping 1 sec ... \n";
    sleep 1;
}   
# regex above may need slight adjustment, depending on format of ps return

通过上面的qx()收到的命令输出(反引号操作符)包含换行符。如果这证明是脚本执行的问题,可以chomp编辑,这需要稍作调整。剩下的漏洞是 非常程序可能已经完成并在检查之间重新启动,并具有相同的PID。

这将通过在shell中运行来测试

sleep 30 &
script.pl `ps aux | egrep '[s]leep'`

egrepgrep -E`ps ...`的输出包含多个单词。它们作为命令行参数传递给我们的脚本,它使用第一个作为PID。如果出现问题,请首先运行ps过滤,然后手动输入PID作为脚本的输入参数。上面30秒的sleep是足够的时间在命令行上完成所有这些操作。

如果程序名称足够独特且不会更改,则可以通过将$name与硬编码$prog_name匹配来简化代码。 上面使用了硬编码名称​​ ,但是对于检查,如果不匹配则会生成警告。 (如果我们只依赖硬编码,如果它不匹配就不能发出警告,因为这是代码操作的一部分。)

如果该进程由与该脚本相同的用户拥有,则可以使用kill 0, $pid作为

while ( kill 0, $ext_pid ) { sleep 1 }

然后你要么再打一次电话来检查名字,要么满足$pid所代表的实际过程中出现错误的可能性(小)。

模块Proc::ProcessTable可用于此

的大部分内容