为什么 File::FcntlLock 的 l_type 总是 "F_UNLCK" 即使文件已锁定?
Why is File::FcntlLock's l_type always "F_UNLCK" even if the file is locked?
下面的 Perl 子例程使用 File::FcntlLock
检查文件是否被锁定。
为什么即使文件被锁定,它 return 0
并打印 /tmp/test.pid is unlocked.
?
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();
}
文件被锁定如下(lock.sh):
#!/bin/sh
(
flock -n 200
while true; do sleep 1; done
) 200>/tmp/test.pid
文件确实被锁定:
~$ ./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
fcntl
和 flock
锁彼此不可见。
这对您的用例来说是个大问题,因为您在 shell 脚本中使用的 flock
实用程序取决于 flock
语义:shell脚本 运行 是一个 flock
子进程,它锁定继承的文件描述符然后退出。 shell 保持该文件描述符打开(因为重定向是针对整个命令序列的)直到它想要释放锁。
该计划不适用于 fcntl
,因为 fcntl
锁不在进程之间共享。如果有一个与 flock
相同但使用 fcntl
的实用程序,则锁会过早释放(只要子进程退出)。
为了协调 perl 进程和 shell 脚本之间的文件锁,您可以考虑的一些选项是:
- 将 shell 脚本移植到
zsh
并使用 zsh/system
模块中的 zsystem flock
内置函数(注意:在文档中它声称使用 fcntl
尽管它的名字是 flock
)
- 用 perl 重写 shell 脚本
- 只需在 perl 脚本中使用 flock(放弃字节范围锁定和 "get locker PID" 功能 - 但您可以通过阅读
/proc/locks
在 Linux 上模拟它)
- 用 C 编写您自己的
fcntl
实用程序以用于 shell 脚本(使用模式会有所不同 - shell 脚本必须将其置于后台,然后将其终止稍后解锁 - 它需要一些方法来告诉父进程何时获得或未能获得锁,这将很难,因为它现在是异步发生的......也许使用 coprocess 某些 shell 具有的功能)。
- 运行 shell 脚本中的一个小 perl 脚本来进行锁定(需要与专用
fcntl
实用程序所需的相同后台处理)
有关不同类型锁的功能的详细信息,请参阅 。
下面的 Perl 子例程使用 File::FcntlLock
检查文件是否被锁定。
为什么即使文件被锁定,它 return 0
并打印 /tmp/test.pid is unlocked.
?
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();
}
文件被锁定如下(lock.sh):
#!/bin/sh
(
flock -n 200
while true; do sleep 1; done
) 200>/tmp/test.pid
文件确实被锁定:
~$ ./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
fcntl
和 flock
锁彼此不可见。
这对您的用例来说是个大问题,因为您在 shell 脚本中使用的 flock
实用程序取决于 flock
语义:shell脚本 运行 是一个 flock
子进程,它锁定继承的文件描述符然后退出。 shell 保持该文件描述符打开(因为重定向是针对整个命令序列的)直到它想要释放锁。
该计划不适用于 fcntl
,因为 fcntl
锁不在进程之间共享。如果有一个与 flock
相同但使用 fcntl
的实用程序,则锁会过早释放(只要子进程退出)。
为了协调 perl 进程和 shell 脚本之间的文件锁,您可以考虑的一些选项是:
- 将 shell 脚本移植到
zsh
并使用zsh/system
模块中的zsystem flock
内置函数(注意:在文档中它声称使用fcntl
尽管它的名字是flock
) - 用 perl 重写 shell 脚本
- 只需在 perl 脚本中使用 flock(放弃字节范围锁定和 "get locker PID" 功能 - 但您可以通过阅读
/proc/locks
在 Linux 上模拟它) - 用 C 编写您自己的
fcntl
实用程序以用于 shell 脚本(使用模式会有所不同 - shell 脚本必须将其置于后台,然后将其终止稍后解锁 - 它需要一些方法来告诉父进程何时获得或未能获得锁,这将很难,因为它现在是异步发生的......也许使用 coprocess 某些 shell 具有的功能)。 - 运行 shell 脚本中的一个小 perl 脚本来进行锁定(需要与专用
fcntl
实用程序所需的相同后台处理)
有关不同类型锁的功能的详细信息,请参阅