Lock Perl子例程

时间:2015-04-22 12:39:43

标签: multithreading perl locking flock

我写了一个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;
}

应该没有等待/队列,并发进程永远不应该调用sub_that_should_be_locked

2 个答案:

答案 0 :(得分:4)

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

检查文件是否已锁定,而不是检查文件是否存在。这是使用非阻塞flock完成的。如果文件尚未锁定,它将返回成功,如果文件已被锁定,它将返回错误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;
}

答案 1 :(得分:1)

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

在线程启动之前,您应确保文件存在,然后子例程应使用词法文件句柄打开输入的锁定文件

喜欢这个

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

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