这三个版本等效吗?
#!/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;
最佳答案
您似乎想要打开一个文件,锁定它,然后截断它,而竞争该锁的另一个进程可能会看到截断的文件。这带来了一些限制:
- 在截断之前必须获得锁。这排除了第一个解决方案,因为它在获取锁之前进行了截断。
- 文件句柄不能用其他模式重新打开,否则锁会丢失。这意味着截断无法通过重新打开来完成。
因此,理想的解决方案具有以下步骤:
- 文件打开时不会被截断,例如使用 sysopen,或打开模式
>>
,+<
。 sysopen 选项O_TRUNC
或打开模式>
,+>
等不得在此处使用。 - 已获取锁。
- 执行截断。如
open
将创建一个新的文件句柄truncate
此处必须使用函数。 - 如果文件是以附加模式打开的,则需要
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/