使用Perl的system函数启动进程,如何获得该进程的PID?

7

我正在编写一个 Perl 脚本 (称为script.pl),它调用另一个脚本 newscript.pl。我想在 script.pl 中仅获取这两个脚本的 PID。可以使用以下代码获取 script.pl 的 PID:

my $pid = Unix::PID->new();
my @p = $pid->get_pidof( $pid->get_command($$), 1 );

在此之后,我调用system来执行newscript.pl
system("perl newscript.pl");

我希望能在script.pl中获取newscript.pl生成的PID。
2个回答

10

当前进程的进程号在 $$ 中。使用open3 代替system 来获取子进程的进程号。


6
system返回时,已经生成的进程将会退出,留下其pid作为历史参考信息,例如用于日志分析。

system LIST
system PROGRAM LIST

exec LIST做的事情完全一样,不同之处在于首先执行一个fork父进程等待子进程退出……

如果您想要script.plnewscript.pl的pid,可以自己进行fork并管理它们的生命周期。如果有更具体的问题信息,我们可以给出更具体的建议。
为了阻止程序的其他实例运行,常用的技术是使用操作系统的协作锁定功能:在启动时尝试锁定某个文件。如果成功,您的程序就知道它是唯一的程序。否则,另一个进程已经拥有了锁定,所以新的进程会退出。请参见下面的示例。
#! /usr/bin/env perl

use strict;
use warnings;

use Fcntl qw/ :flock /;
use File::Basename;
use POSIX qw/ strftime /;

$0 = basename $0;

my $LOCK = "$ENV{HOME}/.lock-$0";

sub logmsg {
  my($msg) = @_;
  my $t = strftime "%F %T", localtime time;
  warn "$0: $t - $$ - $msg\n";
}

sub take_lock {
  open my $fh, ">", $LOCK or die "$0: open $LOCK: $!";

  unless (flock $fh, LOCK_EX | LOCK_NB) {
    logmsg "failed to lock $LOCK; exiting.";
    exit 1;
  }

  $fh;
}

my $token = take_lock;
logmsg "processing...";
sleep 2 * 60;
logmsg "done.";

请注意,在您的临界区内控制时,必须保持从take_lock返回的文件句柄处于打开状态。上面的代码将其视为不透明令牌。当程序退出时,Perl会关闭文件句柄,从而自动释放锁定。您不想做的是在无效上下文中调用take_lock,因为那样会丢弃您的锁定。

我的script.pl负责调度其他脚本,如newscript.pl和许多其他脚本。我不能直接在cron中安排它们,因此想到制作这个父脚本,它将充当调度程序。现在,可能会出现计划的脚本重复执行的情况,因为我从MySql数据库获取脚本名称,我不希望已经运行的脚本再次执行,因此我在考虑是否可以捕获已安排脚本的PIDs,我可以基于这些PIDs进行检查并避免同时运行相同的脚本。非常感谢您的帮助。 - Deepak
有没有其他方法可以在不使用 fork 的情况下完成它? - Deepak
如果您需要独占性,请使用flock()use Fcntl qw(:flock); flock ($lockfd, LOCK_NB|LOCK_EX) or die "Same script already going"; # ...请注意,$lockfd是文件描述符而不是文件名(您必须在flock之前打开它)。 - Dallaylaen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接