使用简单文件实现锁定

Man*_*our 2 perl locking file

我想知道是否有任何方式只有在目标不存在时才能移动文件 - 换句话说,只有在不导致覆盖的情况下才移动.

mv --update
Run Code Online (Sandbox Code Playgroud)

似乎首先是解决方案,但是,如果源路径的时间戳比目标更新,则移动将覆盖它,并且所有通过在移动之前修改时间戳来避免这种情况的尝试都将失败.

我需要这种行为来实现一个简单的基于文件的锁,其中"lock"文件的存在表明已获取锁.

我使用perl执行此任务,因此如果perl具有此功能,则会有所帮助.但是,我需要确保移动操作是原子的.

Gre*_*con 7

但是当别人有锁时你会怎么做?退出并稍后再试?忙等待?

如果你不需要同步,那么一个好的选择是sysopen使用O_EXCLO_CREAT标志设置,只有当文件不存在时才会创建文件.

use Fcntl qw/ :DEFAULT /;

# ...

sysopen my $fh, $LOCKFILE, O_EXCL|O_CREAT
  or die "$0: sysopen: $!";
Run Code Online (Sandbox Code Playgroud)

但请注意Linux open(2)手册页中的以下警告:

O_EXCL仅在内核2.6或更高版本上使用NFSv3或更高版本时在NFS上受支持.在O_EXCL未提供NFS 支持的环境中,依赖它来执行锁定任务的程序将包含竞争条件.想要使用锁文件执行原子文件锁定并且需要避免依赖NFS支持的O_EXCL可移植程序可以在同一文件系统上创建一个唯一的文件(例如,合并主机名和PID),并用于link(2)建立一个链接到锁定文件.如果link(2)返回0,则锁定成功.否则,stat(2)在唯一文件上使用以检查其链接计数是否已增加到2,在这种情况下锁定也是成功的.

"我宁愿拥有一个网络文件系统而不是NFS,"俗话说,所以如果可以,请将协调进程保留在同一台机器上.

您可以考虑flock在下面的代码中使用:

#! /usr/bin/perl

use warnings;
use strict;

use Fcntl qw/ :DEFAULT :flock /;

my $LOCKFILE = "/tmp/mylock";

sub acquire_lock {
  sysopen my $fh, $LOCKFILE, O_RDWR|O_CREAT or die "$0: open: $!";
  flock $fh, LOCK_EX                        or die "$0: flock: $!";
  $fh;
}

sub work {
  for (1 .. 2) {
    my $fh = acquire_lock;
    print "$0: $$ has lock\n";
    sleep rand 3;
    close $fh or warn "$0: [$$] close: $!";
  }
  exit;
}
Run Code Online (Sandbox Code Playgroud)

对于演示,下面的代码分叉五个孩子轮流获取锁:

my $KIDS = 5;
my %pids;
for (1 .. $KIDS) {
  my $pid = fork;
  die "$0: fork: $!" unless defined $pid;

  $pid ? ++$pids{$pid} : work;
}

while (my $pid = wait) {
  last if $pid == -1;
  warn "$0: unknown child $pid" unless delete $pids{$pid};
}

warn "$0: still alive: " .
     join(", " => sort { $a <=> $b } keys %pids) .
     "\n"
  if keys %pids;
Run Code Online (Sandbox Code Playgroud)

样本输出:

./kidlock: 26644 has lock
./kidlock: 26645 has lock
./kidlock: 26646 has lock
./kidlock: 26645 has lock
./kidlock: 26648 has lock
./kidlock: 26646 has lock
./kidlock: 26647 has lock
./kidlock: 26647 has lock
./kidlock: 26644 has lock
./kidlock: 26648 has lock