Perl 模块之Fcntl
2018-05-17 17:44:05 阿炯

Fcntl - load the C Fcntl.h defines

You can request that the flock() constants (LOCK_SH, LOCK_EX, LOCK_NB and LOCK_UN) be provided by using the tag :flock.

use Fcntl qw(SEEK_SET F_WRLCK F_UNLCK F_SETLKW);

Perl flock Function

This function supports file locking on the specified FILEHANDLE using the system flock(), fcntl() locking, or lockf(). The exact implementation used is dependent on what your system supports. OPERATION is one of the static values defined here.
该函数支持使用系统flock()、fcntl()锁定或lockf()来锁定指定的文件句柄。使用的确切实现取决于系统支持的情况,操作符是这里定义的静态值之一,如下:

Operation    Result
LOCK_SH     Set shared lock.
LOCK_EX     Set exclusive lock.
LOCK_UN     Unlock specified file.
LONG_NB     Set lock without blocking.

Syntax(语法)
Following is the simple syntax for this function −

flock FILEHANDLE, OPERATION

Return Value(返回值)

This function returns 0 on failure to set/unset lock and 1 on success to set/unset lock.
失败时返回为0,能成功加、去锁时返回1。

Calls flock(2), or an emulation of it, on FILEHANDLE. Returns true for success, false on failure. Produces a fatal error if used on a machine that doesn't implement flock(2), fcntl(2) locking, or lockf(3). flock is Perl's portable file-locking interface, although it locks entire files only, not records.
调用flock(2)或在文件句柄上进行模拟。成功返回true,失败返回false。如果在不支持flock(2)、fcntl(2)锁定或lockf(3)的机器上使用,会产生致命错误。flock是Perl的可移植文件锁定接口,尽管它只锁定整个文件,而不是记录。

OPERATION is one of LOCK_SH, LOCK_EX, or LOCK_UN, possibly combined with LOCK_NB. These constants are traditionally valued 1, 2, 8 and 4, but you can use the symbolic names if you import them from the Fcntl module, either individually, or as a group using the :flock tag. LOCK_SH requests a shared lock, LOCK_EX requests an exclusive lock, and LOCK_UN releases a previously requested lock. If LOCK_NB is bitwise-or'ed with LOCK_SH or LOCK_EX, then flock returns immediately rather than blocking waiting for the lock; check the return status to see if you got it.
操作符是LOCK_SH、LOCK_EX或LOCK_UN中的之一,可能与LOCK_NB结合。这些常量通常值为1、2、8和4,但如果从Fcntl模块中导入它们,则可以使用符号名称,无论是单独的,还是使用:flock标记的组。LOCK_SH请求一个共享锁,LOCK_EX请求一个独占锁,LOCK_UN释放一个先前请求的锁。如果LOCK_NB是bitwise—或者是带有LOCK_SH或LOCK_EX,那么flock会立即返回,而不是阻塞等待锁;可检查返回状态,看看是否得到了它。

To avoid the possibility of miscoordination(不协调), Perl now flushes FILEHANDLE before locking or unlocking it.
为了避免操作前后的不协调,Perl现在在锁定或解锁之前会先刷新文件句柄。

Note that the fcntl(2) emulation of flock(3) requires that FILEHANDLE be open with read intent to use LOCK_SH and requires that it be open with write intent to use LOCK_EX.
请注意,flock(3)的fcntl(2)模拟请求会要求FILEHANDLE是打开的,读取将使用LOCK_SH,并要求它是打开写之前使用LOCK_EX来加锁。


On many Unix/Linux systems there are actually two independent locking systems: BSD flock() and POSIX fcntl()-based locks.
在大多数Unix/Linux系统中,有两种独立的锁系统:基于BSD的flock()和基于POSIX fcntl()实现。

Unless you provide special options to configure when building Perl, its flock will use flock() if available. This is generally fine and probably what you want if you just need locking within your application (running on a single system). However, sometimes you need to interact with another application that uses fcntl() locks (like Sendmail, on many systems) or perhaps you need to do file locking across NFS-mounted filesystems.
除非提供了在编译Perl时配置的特殊选项,否则它的flock将使用flock()。如果只需要在应用程序中锁定(在单机系统上运行),那么这通常很好,而且可能想要什么就是什么。然而,有时需要与另一个使用fcntl()锁的应用程序进行交互(如Sendmail,在许多系统上),或者可能需要在nfs挂载的文件系统上执行文件锁定。

Quick overview of flock/fcntl/lockf differences:
快速浏览flock/fcntl/lockf差异:

lockf is almost always implemented on top of fcntl, has file-level locking only. If implemented using fcntl, limitations below also apply to lockf.
lockf几乎总是在fcntl之上实现,只有文件级别的锁定。既然使用fcntl实现,下面的限制也适用于lockf。

fcntl provides range-level locking (within a file) and network locking over NFS, but locks are not inherited by child processes after a fork(). On many systems, you must have the filehandle open read-only to request a shared lock, and read-write to request an exclusive lock.
fcntl提供了范围级别的锁定(在一个文件中)和网络锁定NFS,但是在fork()之后,锁不会被子进程继承。在许多系统中,必须让filehandle以只读方式打开,以请求共享锁,读写则请求独占锁。

flock has file-level locking only, locking is only within a single machine (you can lock an NFS-mounted file, but only local processes will see the lock). Locks are inherited by children (assuming that the file descriptor is not closed).
flock只有文件级别的锁定,锁定仅在一个机器内(可以锁定一个nfs挂载的文件,但只有本地进程才能看到锁)。锁可由其fork出来的子进程继承的(在文件描述符没有关闭的情况下)。

Sometimes (SYSV systems) flock is emulated using lockf, or fcntl; on some BSD systems lockf is emulated using flock. Generally these sorts of emulation work poorly and you are well advised to avoid them.
有时(SYSV系统)flock使用lockf或fcntl模拟实现,在一些BSD系统中,lockf使用flock模拟。一般来说,这些模拟工作都很糟糕,你最好避开它们。

最佳示例

示例1:
use Fcntl ':flock'; # import LOCK_* constants

# open the file for appending
open (my $fh, '>>', 'test.dat') or die $!;

# try to lock the file exclusively, will wait till you get the lock
flock($fh, LOCK_EX);

# do something with the file here (print to it in our case)

# actually you should not unlock the file
# close the file will unlock it
close($fh) or warn "Could not close file $!";


示例2:
open (FILE, '>>', test.dat') ; # open the file
flock FILE, 2; # try to lock the file
# do something with the file here
close(FILE); # close the file

示例3:
open (FREEOA,"+< rw.txt") or die "Cannot open file\n$!";
flock(FREEOA, LOCK_EX);
# Read the file:
@LINES=<FREEOA>;
# Wipe the file:
seek(FREEOA, 0, 0); truncate(FREEOA, 0);
# Do something with the contents here:
push @LINES,"grappig, he!\n";
$LINES[3]="Gekke henkie!\n";
# Write the file:
foreach $l (@LINES){
   print FREEOA $l;
}
close(FREEOA) or die "Cannot close file\n$!";

示例4:
use v5.12;
use Fcntl qw(:flock);
my $file = 'freeoa.dat';
# open the file
open (FILE, ">>", "$file") || die "problem opening $file\n";

# immediately lock the file
flock FILE, LOCK_EX;

# intentionally keep the lock on the file for ~20 seconds
my $count = 0;
while ($count++ < 15){
  print FILE $$." => ".time()."\n";
  sleep 1;
}

# close the file, which also removes the lock
close (FILE);

示例5:
use v5.12;
use Fcntl qw(:flock);

my $file = 'freeoa.dat';
my $count = 0;
while ($count++ < 15){
  open (FILE, ">>", "$file") || die "problem opening $file\n";
  # lock the file before i write to it
  flock FILE, LOCK_EX;
  print FILE $$." => ".time()."\n";
  close (FILE);
  sleep 1;
}


参考来源:

Fcntl

fcntl - file control system call

flock - lock an entire file with an advisory lock

初识fcntl文件操作

Perlmonks File Locking

Perl Cookbook ch7.11 Locking a File