在错误的情况下释放羊群?

Posted

技术标签:

【中文标题】在错误的情况下释放羊群?【英文标题】: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 实例在运行,以便清楚哪个脚本在没有释放锁的情况下崩溃/停止?

【问题讨论】:

【参考方案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;

$SIGCHLD = "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 的简短但仍然正确且内容丰富的回复!

以上是关于在错误的情况下释放羊群?的主要内容,如果未能解决你的问题,请参考以下文章

作业帮助,分段错误,双重释放或损坏,free():无效指针

重新激活“HTTP错误代码402”,释放Web 3.0的潜力(下)

文字 NSString 是自动释放还是需要释放?

网络服务错误码解析

这个错误是什么意思? malloc:***对象0x103f000的错误:未分配被释放的指针

为啥我的自动释放对象没有被释放?