我正在寻找一种在 Perl 中实现读/写锁的好方法。
这是在 Windows 和 Unix 上同步来自不同 Perl 线程和/或进程的文件访问所必需的。
试过 Fcntl::flock 如果它按预期工作,这对我来说是完美的。不幸的是,看起来在压力下,群允许在另一个线程中对已锁定的文件设置锁定。
查看了一些 CPAN 模块,但大多数是用 flock 实现的。
接下来我计划评估 fcntl for Unix 和 Win32::Mutex for Windows。
这似乎是一项非常常见的任务,也许我缺少一些简单的解决方案。
如果你知道任何,你能帮我指出吗?
谢谢!
最佳答案
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;
最好使用 File::Temp 作为锁文件名,但请仔细阅读文档以了解细节。
具有 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
may be unsuppored under NFS: you must have at least 2.6 kernel and NFSv3 or there will be a race condition. If this is a problem the workaround is to use link(2)
to obtain a lock. See man 2 open
(also for other details since sysopen
uses open
syscall).
To lock only file access, for example
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
和 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;
使用第一个示例中的
use
语句和 3 个分支,运行(18956: "lock"-file exists ..) # 乱序打印
18954 (#1) 打开 t_LOCK.txt ...
(18955:“锁定”文件存在..)
(18956:“锁定”文件存在..)
(18955:“锁定”文件存在..)
(18954:释放锁)
18954 (#1) 关闭 t_LOCK.txt。
---
18956 (#3) 打开 t_LOCK.txt ...
(18955:“锁定”文件存在..)
(18956:释放锁)
18956 (#3) 关闭 t_LOCK.txt。
---
18955 (#2) 打开 t_LOCK.txt ...
(18955:释放锁)
18955 (#2) 关闭 t_LOCK.txt。
---
这是 18954 (#1)
这是 18956 (#3)
这是 18955 (#2)
(请注意,独立进程正在争取
STDOUT
)关于multithreading - Perl 中的读写锁,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46818084/