multithreading - Perl 中的读写锁

标签 multithreading perl

我正在寻找一种在 Perl 中实现读/写锁的好方法。
这是在 Windows 和 Unix 上同步来自不同 Perl 线程和/或进程的文件访问所必需的。
尝试了 Fcntl::flock 如果它按预期工作对我来说将是完美的。不幸的是,在压力下,flock 似乎允许在另一个线程中对已锁定的文件设置锁定。
研究了一些 CPAN 模块,但大多数都是用flock实现的。
接下来我计划评估 fcntl 用于 Unix 和 Win32::Mutex 用于 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 个 fork ,运行

(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/

相关文章:

c++ - pthread 窗口崩溃 C++

sql - 选择 FOR UPDATE SKIP LOCKED 时,为什么行对多个 session 可见?

c++ - 如何使线程函数自包含

perl - 在Perl中循环遍历一系列哈希

Perl 模块类方法 vs 普通子程序

python - 如何比较两个文件并打印仅与第一个文件匹配的第二个文件

bash - Bash 中的 Perl : How to read from pipe and pass arguments to perl at the same time?

java - 在对象上同步似乎没有同步

multithreading - Delphi 多线程消息循环

perl - 创建新的 Net::SMTP::SSL 对象时无提示失败