Flock:使用系统打开截断的正确方法



这三个版本等效吗?

#!/usr/bin/env perl
use warnings;
use strict;
use 5.10.0;
use Fcntl qw(:flock :seek);
my $fh;
sysopen $fh, $file, O_WRONLY | O_CREAT | O_TRUNC or die $!;
flock $fh, LOCK_EX or die $!;
say $fh 'something';
close $fh;
sysopen $fh, $file, O_WRONLY | O_CREAT or die $!;
flock $fh, LOCK_EX or die $!;
seek $fh, 0, SEEK_SET or die $!;
truncate $fh, 0 or die $!;
say $fh 'something';
close $fh;
sysopen $fh, $file, O_WRONLY | O_CREAT or die $!;
flock $fh, LOCK_EX or die $!;
truncate $fh, 0 or die $!;
say $fh 'something';
close $fh;

您似乎想打开一个文件,锁定它,然后截断它,而另一个竞争该锁的进程可能会看到截断的文件。这带来了几个限制:

  • 必须在截断之前获得锁。这排除了第一种解决方案,因为它在获取锁之前进行了截断。
  • 文件句柄无法使用其他模式重新打开,否则锁将丢失。这意味着无法通过重新打开来截断。

因此,理想的解决方案具有以下步骤:

    打开
  1. 文件时不会截断,例如使用系统打开或打开模式>>+<。此处不得使用 sysopen 选项O_TRUNC或打开模式>+> 等。
  2. 获取锁。
  3. 执行截断。由于open将创建新的文件句柄,因此必须在此处使用 truncate 函数。
  4. 如果文件是在追加模式下打开的,则需要seek到文件的开头。

您的第一个解决方案在获取锁之前截断,因此可以排除。

您的第二种和第三种解决方案都是可能的,尽管seek是不必要的。

其他解决方案可以使用常规open

open my $fh, "+<", $file;  # Achtung: fails if the file doesn't exist
flock $fh, LOCK_EX;
truncate $fh;
# or:
open my $fh, ">>", $file;
flock $fh, LOCK_EX;
truncate $fh;
seek 0, 0;

在许多情况下,最好使用不相关的文件作为锁定,从而避免重新打开的困难。这看起来像:

# adapted from perldoc -f flock
sub lock {
  my $file = shift;
  open my $fh, "<", ".$file.lock";
  flock $fh, LOCK_EX;
  return $fh;
}
sub unlock {
  my $fh = shift;
  flock $fh, LOCK_UN;
}
my $lock = lock($file);
open my $fh, ">", $file;
...
unlock($lock);

当然,所有相关进程都必须遵循此接口并创建适当的锁文件。

相关内容

  • 没有找到相关文章

最新更新