如何在运行进程不是子进程时等待运行进程在perl中完成?
我正在使用一个Perl脚本,它使用 waitpid($pid, 0)
等待当前进程完成。 但是print
在此之后编写的陈述waitpid
在过程完成之前正在打印它。如何在运行进程不是子进程时等待运行进程在perl中完成?
我想知道为什么waitpid
不是先等待流程完成。
此外,运行过程的控制是在不同的模块下,而不是这个perl脚本的一部分。只能访问进程的pid和名称。我无法更改调用该过程的模块中的任何内容。
备注 kill 0, $pid
最后一个简单的单线发表评论。
我们需要检测一个外部程序的完成,这个脚本还没有启动。该问题询问使用waitpid
。复制我的早评:
你不能。您只能等待子进程。见
perldoc wait
(或waitpid
,这是一样的),第一句话。
wait
和waitpid
等待传递给脚本的关于其子(命令)的命运的信号。脚本没有理由接收有关它没有启动的进程的信号。
我们知道进程的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'`
的egrep
是grep -E
运行进行测试。 `ps ...`
的输出包含多个单词。这些作为命令行参数传递给我们的脚本,该脚本使用第一个作为PID。如果出现问题,请先运行ps
筛选,然后手动输入PID作为脚本的输入参数。上面30秒的sleep
是给予足够的时间在命令行上完成所有这些。
如果程序名称足够独特且不会更改,则可以通过将$name
与硬编码的$prog_name
进行匹配来简化代码。 上面使用的硬编码名称是,但是对于检查,如果不匹配,它会生成警告。如果这个过程是由相同的用户脚本可以使用kill 0, $pid
资(如果我们依靠它只能硬编码,我们不能发出警告,如果不匹配,因为这是随后的代码的操作的一部分。)
作为
while (kill 0, $ext_pid) { sleep 1 }
然后,你要么必须拨打另一个电话,以检查名称或满足于在什么实际过程中$pid
表示错误的(小)的可能性。
模块Proc::ProcessTable
可以用于所有这些。在Windows系统上,这将是一条路。
是的,它为我工作 – user3395103
@ user3395103很高兴工作。结果是一个很长的帖子,让我知道是否有任何问题或问题。 – zdim
等待特定子进程终止,并返回死者进程的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(不太可能,但可能)。
您确定'$ pid'是您认为的吗? 'waitpid'的返回值是什么?它将指示什么进程终止。 – Schwern
@Schwern - waitpid的返回值是-1。这意味着我没有这样的孩子过程。我添加下面的行来检查$ pid是否正在运行。我的$ exists = kill 0,$ pid; ($存在);打印“进程正在运行\ n”( );并且它会打印语句 – user3395103
您不能。您只能在子进程上“等待”。请参阅'perldoc wait'(或'waitpid',这是一样的),第一句。如果你想知道外部程序何时完成,你必须做完全不同的事情。 – zdim