perl - 集群:用sysopen截断的正确方法

标签 perl file-io truncate 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,或打开模式 >> , +< 。 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);

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

关于perl - 集群:用sysopen截断的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18804652/

相关文章:

html - 表格单元格中的空白 :'nowrap' 破坏表格布局 :'auto' : how to fix it?

perl - 为什么Perl不编译为python之类的二进制文件

perl - 使用闭包修改 Perl BEGIN block 中的类

c# - 获取具有特定最后修改日期的所有文件的列表

c - 写入/读取二进制保存游戏

java - 读取日志文件并将其显示在 jTextArea 中

python - 负前瞻正则表达式贪婪(为什么.*?太贪婪)

perl - GTK3 触摸屏上的组合框文本

php - 没有重复条目时的mysql重复条目错误(通过php批量加载)

mongodb - 聚合截断日期函数?