4

我需要确保一次只运行我的 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;
    } 
}

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

4

4 回答 4

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变量的好地方。

于 2010-10-19T08:31:47.477 回答
2

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

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

(来自perldoc -f flock

注意fcntl(2) 模拟flock(3) 要求FILEHANDLE 以读取意图打开以使用LOCK_SH,并要求FILEHANDLE 以写入意图打开以使用LOCK_EX。

于 2010-10-19T15:03:41.903 回答
2

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

于 2010-10-19T14:59:05.097 回答
1

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

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

于 2010-10-19T08:30:46.387 回答