【问题标题】:Release of flock in case of errors?在错误的情况下释放羊群?
【发布时间】:2012-09-20 23:47:35
【问题描述】:

想象一下下面的 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 实例在运行,以便清楚哪个脚本在没有释放锁的情况下崩溃/停止?

【问题讨论】:

    标签: linux perl locking flock


    【解决方案1】:

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

    【讨论】:

    • 如果没有任何证据证明你是对的,这个答案是没有用的。
    【解决方案2】:

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

    所有这些问题都取决于系统。 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 进程。

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

    【讨论】:

    • 非常详细的回答,非常感谢!还要感谢 soulSurfer2010 的简短但仍然正确且内容丰富的回复!
    猜你喜欢
    • 1970-01-01
    • 2012-06-14
    • 2014-08-16
    • 1970-01-01
    • 2014-07-12
    • 1970-01-01
    • 2016-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多