锁定 Perl 子例程

Lock Perl sub routine

我写了一个CGI脚本。它的子程序之一不能同时执行。即同一用户(或黑客)运行 完全相同的两个实例)。我怎样才能避免这种情况?

我使用锁定文件进行了以下变通,但我不确定它是否安全:

unless (-e $filelock) {
    sub_that_should_be_locked();
}


sub sub_that_should_be_locked {
    open FILE, ">", $filelock;
    flock DATAFILE, LOCK_EX;
    close FILE;

    ...Code that cannot be executed at the same time...   
    ...Code that cannot be executed at the same time...

    unlink $filelock;
}

不应该有 waiting/queue,并发进程不应该调用 sub_that_should_be_locked

您要同步的线程不应创建和删除锁文件。

你应该确保文件存在 before 线程被启动,然后子例程应该使用 lexical 文件句柄来打开input.

的锁定文件

像这样

open my $lock_fh, '<', $lockfile or die $!;
flock $lock_fh, LOCK_EX;

作为它的第一个动作。这将挂起线程,直到它在队列中被连接,之后文件将在子例程结束时隐式关闭(并因此释放其锁),因为 $lock_fh 超出范围

不安全。您的代码中存在竞争条件,因为 -eopen 之间存在时间。永远不要将 -e 与锁定文件一起使用。

不检查文件是否存在,而是检查文件是否已经被锁定。这是使用非阻塞 flock 完成的。如果文件尚未锁定,它将 return 成功,如果文件已被锁定,它将 return 错误 EWOULDBLOCK

请注意,要使其正常工作,您必须在 sub_that_should_be_locked 执行的整个过程中一直持有锁。 (您的代码一获取就释放。)

use Fcntl qw( LOCK_EX LOCK_NB );

sub get_lock_nb {
   my ($qfn) = @_;

   open(my $fh, '+>:raw', $qfn)
      or die("Unable to open file \"$qfn\": $!\n");

   if (!flock($fh, LOCK_EX | LOCK_NB)) {
      return undef if $!{EWOULDBLOCK};
      die("Unable to lock file \"$qfn\": $!\n");
   }

   return $fh;
}

sub sub_that_should_be_locked {
   ... Mutually exclusive code ...
}

{
   my $lock = get_lock_nb("file.lock");
   sub_that_should_be_locked() if $lock;
}