The flock
不会跨线程做你想做的事情。
您可以使用以下方法实现自己的锁定sysopen,如果文件存在,则失败O_EXCL|O_CREAT
.
子进程竞争锁的示例
use warnings;
use strict;
use feature 'say';
use Fcntl;
use Time::HiRes qw(sleep);
my $lock_file = ".lock.$$";
sub get_lock {
my ($file, $pid) = @_;
my $fh;
while (not sysopen $fh, $file, O_WRONLY|O_EXCL|O_CREAT) {
say "\t($$: lock-file exists ..)";
sleep 0.5;
}
say $fh $pid;
}
sub release_lock {
my ($file, $pid) = @_;
unlink $file or die "Error unliking $file: $!";
say "\t($$: released lock)";
}
my @pids;
for (1..4) {
my $pid = fork // die "Can't fork: $!";
if ($pid == 0) {
sleep rand 1;
get_lock($lock_file, $$);
say "$$, locked and processing";
sleep rand 1;
release_lock($lock_file, $$);
say "$$ completed.";
exit
}
push @pids, $pid;
}
wait for @pids;
比较好用文件::临时文件获取锁定文件名称,但请仔细阅读文档以了解其中的细微差别。
3 个进程的输出示例
3659, locked and processing
(3660: lock-file exists ..)
(3658: lock-file exists ..)
(3659: released lock)
3659 completed.
3660, locked and processing
(3658: lock-file exists ..)
(3658: lock-file exists ..)
(3660: released lock)
3660 completed.
3658, locked and processing
(3658: released lock)
3658 completed.
The O_EXCL
NFS 下可能不受支持:您必须至少具有 2.6 内核和 NFSv3,否则将会出现竞争条件。如果这是一个问题,解决方法是使用link(2)
来获取锁。看man 2 open
(还有其他详细信息,因为sysopen
uses open
系统调用)。
例如,仅锁定文件访问
sub open_with_lock {
my ($file, $mode) = @_;
get_lock($lock_file, $$);
open my $fh, $mode, $file or die "Can't open $file: $!";
return $fh;
}
sub close_and_release {
my ($fh) = @_;
close $fh;
release_lock($lock_file, $$);
return 1;
}
这些可以与以下一起放置在模块中get_lock
and release_lock
,例如,锁文件名作为包全局。
一个简单的测试驱动程序
# use statements as above
use Path::Tiny; # only to show the file
my $lock_file = ".lock.file.access.$$";
my $file = 't_LOCK.txt';
my @pids;
for (1..4)
{
my $pid = fork // die "Can't fork: $!";
if ($pid == 0) {
sleep rand 1;
my $fh = open_with_lock($file, '>>');
say "$$ (#$_) opening $file ..";
say $fh "this is $$ (#$_)";
sleep rand 1;
close_and_release($fh);
say "$$ (#$_) closed $file.";
say '---';
exit;
}
push @pids, $pid;
}
wait for @pids;
print path($file)->slurp;
unlink $file;
With use
第一个示例中的语句和 3 个叉子,一次运行
(18956: "lock"-file exists ..) # print out of order
18954 (#1) opening t_LOCK.txt ...
(18955: "lock"-file exists ..)
(18956: "lock"-file exists ..)
(18955: "lock"-file exists ..)
(18954: released lock)
18954 (#1) closed t_LOCK.txt.
---
18956 (#3) opening t_LOCK.txt ...
(18955: "lock"-file exists ..)
(18956: released lock)
18956 (#3) closed t_LOCK.txt.
---
18955 (#2) opening t_LOCK.txt ...
(18955: released lock)
18955 (#2) closed t_LOCK.txt.
---
this is 18954 (#1)
this is 18956 (#3)
this is 18955 (#2)
(请注意,独立进程正在争取STDOUT
)