如何确保一次只运行一个Perl脚本的副本?

时间:2010-10-19 08:24:05

标签: perl locking process flock

我需要确保一次只运行一个Perl脚本副本。根据建议here我写了一个子进行检查:

sub check_instances {
    open my $fh, '<', $0 or die $!; 

    unless (flock($fh, LOCK_EX|LOCK_NB)) {
        print "$0 is already running. Exiting.\n";
        exit 1;
    } 
}

但它不起作用。可能是什么问题?

4 个答案:

答案 0 :(得分:5)

你正在使用一个范围内的词法文件句柄。当check_instances返回时,文件句柄会自动关闭,从而释放锁定。所以你永远不会看到冲突,除非两个副本完全同时检查。

只要脚本正在运行(或者只要您想保持锁定),请确保文件句柄保持打开状态。例如:

{
my $fh;
sub check_instances {
    return if $fh; # We already checked
    open $fh, '<', $0 or die $!; 

    unless (flock($fh, LOCK_EX|LOCK_NB)) {
        print "$0 is already running. Exiting.\n";
        exit 1;
    } 
}
} # end scope of $fh

如果您需要Perl 5.10,这也是使用state variable的好地方。

答案 1 :(得分:2)

您可以检查其他实例的进程列表(Proc::ProcessTable可以提供帮助),但unix程序使用多种语言的常用路径是创建一个pid文件 - 请参阅File::Pid

答案 2 :(得分:2)

flock的正常语义可能要求您以写入模式打开文件句柄,例如

open $fh, '>>', $0;
open $fh, '+<', $0;

(来自perldoc -f flock

  

请注意,flock(3)的fcntl(2)仿真需要这样做      FILEHANDLE打开时具有读取意图以使用LOCK_SH并且需要      它是打开写入意图使用LOCK_EX。

答案 3 :(得分:1)

由于各种原因(例如,如果文件位于NFS等网络文件系统上),文件锁定可能会失败。

我的解决方案是在脚本运行时创建目录。创建目录始终是原子操作。