在这种情况下,操作系统是否会释放锁定?它是否能够识别“嘿,获取锁的脚本崩溃了”并释放锁定?它是否立即释放锁定?
所有这些问题都取决于操作系统。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
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
use strict;
use warnings;
$SIG{CHLD} = "IGNORE";
die "could not fork: $!" unless defined(my $pid = fork);
unless ($pid) {
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) {
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
进程。
注意:如果父进程获取锁并在加锁前没有释放它,则即使父进程退出,子进程仍将拥有相同的锁。