想象以下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实例,以便清楚地知道哪个脚本崩溃/停止而不释放锁?
在那种情况下,操作系统是否释放过该锁? 它是否看到“嘿,获取锁的脚本崩溃了”并释放了锁? 它会立即释放锁吗?
所有这些问题都取决于系统。Perl 5并没有实现文件锁定功能,它只是提供了flock(2),fcntl(2)锁定或lockf(3)(取决于OS中可用的功能)的通用接口。程序退出,segfaults或被sigkill杀死时所发生的情况之间也可能存在差异。
flock(2)
fcntl(2)
lockf(3)
在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:
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它:
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:
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过程。
perl
注意:如果父进程获得了锁并且在锁之前没有放弃,那么即使父进程退出,子进程也将拥有相同的锁。