我正在使用正在使用的Perl脚本
waitpid($pid, 0)
等待当前进程完成。
但是在此print
之后写的waitpid
语句在进程完成之前打印它。
我想知道为什么waitpid
没有等待首先完成流程。
此外,对运行进程的控制在不同的模块下,而不是这个perl脚本的一部分。只有可访问的是进程的pid和名称。我无法更改调用该过程的模块中的任何内容。
答案 0 :(得分:3)
等待特定的子进程终止并返回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
,它是相同的),第一句话。
wait
和waitpid
等待传递给脚本的关于其子(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'`
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
可用于此