我需要确保一次只运行我的perl脚本的一个副本。根据建议 这里 我写了一个子来进行检查:

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;
    } 
}

但这行不通。有什么问题?

有帮助吗?

解决方案

您正在使用子内部范围内的词汇filehandle。什么时候 check_instances 返回,FileHandle自动关闭,从而释放锁。因此,除非有两份副本同时进行检查,否则您将永远不会看到冲突。

只要脚本正在运行(或只要要维护锁),请确保文件打开。例如:

{
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

这也将是一个使用的好地方 state 多变的, ,如果您需要Perl 5.10。

其他提示

您可以检查其他实例的过程列表(proc :: processTable 可以提供帮助),但是Unix程序以多种语言采取的一条通用路线是创建一个PID文件 - 请参阅 文件:: pid.

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

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

(从 perldoc -f flock)

请注意,FCNTL(2)FLOCK(3)的仿真要求使用读取意图打开fileHandle,以使用lock_sh,并要求它以写入意图打开以使用lock_ex。

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top