为什么File :: FcntlLock的l_type总是“F_UNLCK”,即使文件被locking?

下面的Perl子程序使用File::FcntlLock来检查文件是否被locking。

为什么它返回0 ,打印/tmp/test.pid is unlocked. 即使文件被locking?

 sub getPidOwningLock { my $filename = shift; my $fs = new File::FcntlLock; $fs->l_type( F_WRLCK ); $fs->l_whence( SEEK_SET ); $fs->l_start( 0 ); $fs->l_len( 0 ); my $fd; if (!open($fd, '+<', $filename)) { print "Could not open $filename\n"; return -1; } if (!$fs->lock($fd, F_GETLK)) { print "Could not get lock information on $filename, error: $fs->error\n"; close($fd); return -1; } close($fd); if ($fs->l_type() == F_UNLCK) { print "$filename is unlocked.\n"; return 0; } return $fs->l_pid(); } 

该文件被locking如下(lock.sh):

 #!/bin/sh ( flock -n 200 while true; do sleep 1; done ) 200>/tmp/test.pid 

该文件确实被locking:

 ~$ ./lock.sh & [2] 16803 ~$ lsof /tmp/test.pid COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME bash 26002 admin 200w REG 8,5 0 584649 test.pid sleep 26432 admin 200w REG 8,5 0 584649 test.pid 

fcntlflock锁是彼此不可见的。

这对于你的用例来说是个大问题,因为你在shell脚本中使用的flock工具依赖于flock语义:shell脚本运行一个flock子进程,它锁定一个继承的文件描述符,然后退出。 shell将该文件描述符保持打开状态(因为重定向是在一个完整的命令序列上),直到它想释放锁。

该计划无法与fcntl因为fcntl锁不在进程之间共享。 如果有一个与flock相同的实用程序,但是使用fcntl ,锁定会被释放得太早(一旦子进程退出)。

为了协调perl进程和shell脚本之间的文件锁定,可以考虑一些选项:

  • 将shell脚本移植到zsh并使用zsh/system模块中的zsystem flock内建(注意:尽管它的名字是flock ,但在文档中声明使用fcntl
  • 在perl中重写shell脚本
  • 只要在Perl脚本中使用flock(放弃字节范围锁定和“获取锁定器PID”功能 – 但您可以通过读取/proc/locks来模拟Linux)
  • 在C语言中编写自己的fcntl实用程序以便在shell脚本中使用(使用模式将有所不同 – shell脚本必须将其后台化,然后在解锁时终止),并且需要一些方法告诉父进程已经获得或未能获得锁,这将是很难的,因为它现在异步发生…也许使用一些shell有的协处理功能)。
  • 从shell脚本运行一个小的perl脚本来执行锁定(将需要与专用的fcntl实用程序需要的相同的背景处理)

有关不同种类的锁的更多信息,请参阅fcntlflock锁定有何区别 。