错误情况下释放flock?

18

想象一下以下的 Perl 代码(这里是伪代码):

successfully acquired flock for FILEHANDLER       # line 1
some error or maybe simply a call to exit()       # line 2
close FILEHANDLER (which also releases the lock)  # line 3
在这种情况下,我不会释放锁,因为Perl脚本在第2行就结束了。那么,操作系统是否会释放锁呢?它是否会看到“嘿,获取锁的脚本崩溃了”并释放锁?它是否立即释放锁?另外,每个脚本运行一个Perl实例,这样哪个脚本崩溃/停止而没有释放锁就很清楚了吗?
2个回答

44
在这种情况下,操作系统是否会释放锁定?它是否能够识别“嘿,获取锁的脚本崩溃了”并释放锁定?它是否立即释放锁定?
所有这些问题都取决于操作系统。Perl 5没有实现文件锁定功能,它只提供了一个常见接口,用于flock(2),fcntl(2)锁定或lockf(3)(具体取决于操作系统中可用的内容)。当程序退出、段错误或被sigkill杀死时,情况也可能有所不同。
在Linux下进行的快速测试表明,在正常退出条件下会删除锁定。
$ perl -le 'open my $fh, ">", "f" or die $!; print flock($fh, 6) ? "got lock" : "was already locked", "\n"'
got lock
$ perl -le 'open my $fh, ">", "f" or die $!; print flock($fh, 6) ? "got lock" : "was already locked", "\n"'
got lock

让我们看看当我们调用die函数时会发生什么:

$ perl -le 'open my $fh, ">", "f" or die $!; print flock($fh, 6) ? "got lock" : "was already locked", "\n"; die "died"'
got lock
died at -e line 1.
$ perl -le 'open my $fh, ">", "f" or die $!; print flock($fh, 6) ? "got lock" : "was already locked", "\n"; die "died"'
got lock
died at -e line 1.
为了引起段错误,我们需要访问C语言,我将使用Inline来实现:
$ cat segfault.pl
#!/usr/bin/perl

use strict;
use warnings;

use Inline "C";

open my $fh, ">", "f" or die $!;

print flock($fh, 6) ? "got lock" : "was already locked", "\n";

crash();

__DATA__
__C__

void crash() {
    int* ptr = NULL;
    *ptr = 5;
}
$ perl segfault.pl
got lock
Segmentation fault
$ perl segfault.pl
got lock
Segmentation fault

最后,当一个程序收到SIGKILL信号时会发生什么:

$ cat fork.pl
#!/usr/bin/perl

use strict;
use warnings;

$SIG{CHLD} = "IGNORE"; #auto-reap children

die "could not fork: $!" unless defined(my $pid = fork);
unless ($pid) {
    #child
    open my $fh, ">", "f" or die $!;
    print flock($fh, 6) ? "got lock" : "was already locked", "\n";
    sleep(100);
    exit;
}

kill 9, $pid;

die "could not fork: $!" unless defined($pid = fork);
unless ($pid) {
    #child
    open my $fh, ">", "f" or die $!;
    print flock($fh, 6) ? "got lock" : "was already locked", "\n";
    exit;
}
$ perl fork.pl
got lock
got lock

根据这些实验,我们可以看到在你所关注的每种情况下,Linux都会释放锁。

此外,每个脚本是否有一个独立的perl实例以便清楚地知道哪个脚本崩溃/停止而未释放锁?

是的,Perl 5每个脚本都有一个独立的 perl 进程。 即使您进行了分叉,子进程也会有自己的 perl 进程。 线程不会提供独立的 perl 进程。

注意:如果父进程获取锁并在加锁前没有释放它,则即使父进程退出,子进程仍将拥有相同的锁。


7
非常感谢你提供详细的答案!同时也感谢soulSurfer2010提供简短但仍然正确和有信息量的回复! - stefan.at.kotlin

6
程序退出时,操作系统会自动释放程序获取的所有锁并关闭程序打开的所有文件。

2
没有任何证据证明你是正确的,这个答案就没有用处。 - Mark Amery

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接