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

问题描述:

我正在使用一个Perl脚本,它使用 waitpid($pid, 0)等待当前进程完成。 但是print在此之后编写的陈述waitpid在过程完成之前正在打印它。如何在运行进程不是子进程时等待运行进程在perl中完成?

我想知道为什么waitpid不是先等待流程完成。

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

+0

您确定'$ pid'是您认为的吗? 'waitpid'的返回值是什么?它将指示什么进程终止。 – Schwern

+0

@Schwern - waitpid的返回值是-1。这意味着我没有这样的孩子过程。我添加下面的行来检查$ pid是否正在运行。我的$ exists = kill 0,$ pid; ($存在);打印“进程正在运行\ n”( );并且它会打印语句 – user3395103

+2

您不能。您只能在子进程上“等待”。请参阅'perldoc wait'(或'waitpid',这是一样的),第一句。如果你想知道外部程序何时完成,你必须做完全不同的事情。 – zdim

备注   kill 0, $pid最后一个简单的单线发表评论。


我们需要检测一个外部程序的完成,这个脚本还没有启动。该问题询问使用waitpid。复制我的早评:

你不能。您只能等待子进程。见perldoc wait(或waitpid,这是一样的),第一句话。

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


我们知道进程的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 -ed,这需要稍微调整。其余的漏洞是很程序可能已经完成并且在检查之间重新启动,并且具有相同的PID。

这将通过在壳

 
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可以用于所有这些。在Windows系统上,这将是一条路。

+0

是的,它为我工作 – user3395103

+0

@ user3395103很高兴工作。结果是一个很长的帖子,让我知道是否有任何问题或问题。 – zdim

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 

你还是会需要轮询(睡眠循环)为PID消失。另外请记住,受监视的进程可能会退出,并且在下次检查之前新的可能会重复使用相同的PID(不太可能,但可能)。