flock FILEHANDLE,OPERATION

在 FILEHANDLE 上调用 flock(2) 或其模拟。成功时返回 true,失败时返回 false。如果在未实现 flock(2)fcntl(2) 锁定或 lockf(3) 的机器上使用,则会产生致命错误。flock 是 Perl 的可移植文件锁定接口,尽管它只锁定整个文件,而不是记录。

flock 的两个可能不明显但传统的语义是,它会无限期地等待,直到授予锁,并且其锁仅仅是建议性的。此类自由裁量锁更灵活,但提供的保证更少。这意味着没有也使用 flock 的程序可能会修改使用 flock 锁定的文件。有关详细信息,请参阅 perlport、端口的特定文档和系统特定的本地手册页。如果您编写的是可移植程序,最好假设传统行为。(但如果您不是,您应该始终可以随意为自己的系统特质(有时称为“特性”)编写程序。对可移植性的奴性坚持不应该妨碍您完成工作。)

OPERATION 是 LOCK_SH、LOCK_EX 或 LOCK_UN 之一,可能与 LOCK_NB 结合使用。这些常量传统上分别为 1、2、8 和 4,但如果您从 Fcntl 模块导入它们,则可以使用符号名称,可以单独导入,也可以使用 :flock 标记作为一组导入。LOCK_SH 请求共享锁,LOCK_EX 请求独占锁,LOCK_UN 释放先前请求的锁。如果 LOCK_NB 与 LOCK_SH 或 LOCK_EX 按位或运算,则 flock 会立即返回,而不是阻塞等待锁;检查返回状态以查看您是否已获取锁。

为了避免协调不当的可能性,Perl 现在在锁定或解锁 FILEHANDLE 之前会刷新 FILEHANDLE。

请注意,使用 lockf(3) 构建的仿真不提供共享锁,并且要求 FILEHANDLE 以写入意图打开。这些是 lockf(3) 实现的语义。尽管并非所有系统都实现 lockf(3),但大多数系统都是根据 fcntl(2) 锁定实现的,因此不同的语义不会影响太多人。

请注意,fcntl(2)flock(3) 的仿真要求 FILEHANDLE 以读取意图打开才能使用 LOCK_SH,并且要求 FILEHANDLE 以写入意图打开才能使用 LOCK_EX。

另请注意,某些版本的 flock 无法锁定网络上的内容;您需要使用更特定于系统的 fcntl 来执行此操作。如果您愿意,您可以强制 Perl 忽略您系统的 flock(2) 函数,并提供它自己的基于 fcntl(2) 的仿真,方法是在配置和构建新 Perl 时将开关 -Ud_flock 传递给 Configure 程序。

下面是 BSD 系统的邮箱追加程序。

# import LOCK_* and SEEK_END constants
use Fcntl qw(:flock SEEK_END);

sub lock {
    my ($fh) = @_;
    flock($fh, LOCK_EX) or die "Cannot lock mailbox - $!\n";
    # and, in case we're running on a very old UNIX
    # variant without the modern O_APPEND semantics...
    seek($fh, 0, SEEK_END) or die "Cannot seek - $!\n";
}

sub unlock {
    my ($fh) = @_;
    flock($fh, LOCK_UN) or die "Cannot unlock mailbox - $!\n";
}

open(my $mbox, ">>", "/usr/spool/mail/$ENV{'USER'}")
    or die "Can't open mailbox: $!";

lock($mbox);
print $mbox $msg,"\n\n";
unlock($mbox);

在支持真正的 flock(2) 的系统上,锁在 fork 调用中继承,而必须使用任性的 fcntl(2) 函数的系统会丢失锁,这使得编写服务器变得非常困难。

另请参阅 DB_File 以了解其他 flock 示例。

可移植性问题:perlport 中的“flock”