一尘不染

发生错误时释放羊群?

linux

想象以下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实例,以便清楚地知道哪个脚本崩溃/停止而不释放锁?


阅读 205

收藏
2020-06-07

共1个答案

一尘不染

在那种情况下,操作系统是否释放过该锁?
它是否看到“嘿,获取锁的脚本崩溃了”并释放了锁?
它会立即释放锁吗?

所有这些问题都取决于系统。Perl
5并没有实现文件锁定功能,它只是提供了flock(2)fcntl(2)锁定或lockf(3)(取决于OS中可用的功能)的通用接口。程序退出,segfaults或被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过程。

注意:如果父进程获得了锁并且在锁之前没有放弃,那么即使父进程退出,子进程也将拥有相同的锁。

2020-06-07