在那种情况下,操作系统是否曾经释放过锁?
它是否看到“嘿,获取锁的脚本崩溃”并释放锁?
它会立即释放锁吗?
所有这些问题都取决于系统。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 5perl
每个脚本都有一个进程。即使你分叉,孩子也会有自己的perl
进程。线程不提供单独的perl
进程。
注意:如果父进程获得了锁并且在锁定之前没有放弃它,那么即使父进程退出,子进程也将拥有相同的锁。