Freigabe der Herde bei Fehlern?
Frage
Stellen Sie sich den folgenden Perl-Code vor (hier im Pseudocode):
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
In diesem Fall würde ich die Sperre nicht aufheben, da das Perl-Skript in Zeile 2 endet.Wird die Sperre in diesem Fall jemals vom Betriebssystem freigegeben?Sieht es "Hey, das Skript, das die Sperre erworben hat, ist abgestürzt" und gibt die Sperre auf?Gibt es die Sperre sofort frei?Wird für jedes Skript auch eine Perl-Instanz ausgeführt, damit klar ist, welches Skript abgestürzt / gestoppt wurde, ohne die Sperre aufzuheben?
Lösung
Wird die Sperre in diesem Fall jemals vom Betriebssystem freigegeben?
Sieht es "Hey, das Skript, das die Sperre erworben hat, ist abgestürzt" und gibt die Sperre auf?
Gibt es die Sperre sofort frei?
All diese Fragen sind systemabhängig.Perl 5 implementiert keine Dateisperrfunktion, sondern bietet lediglich eine gemeinsame Schnittstelle zu flock(2)
, fcntl(2)
verriegelung oder lockf(3)
(abhängig davon, was im Betriebssystem verfügbar ist).Es kann auch einen Unterschied geben, was passiert, wenn ein Programm beendet wird, segfault oder mit einem Sigkill beendet wird.
Ein schneller Test unter Linux zeigt, dass eine Sperre unter normalen Exit-Bedingungen entfernt wird:
$ 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
Mal sehen, was passiert, wenn wir 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.
Um einen Segfault zu erhalten, benötigen wir Zugriff auf C, das ich benutze Inline
um es zu bekommen:
$ 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
Und schließlich passiert Folgendes, wenn ein Programm gesendet wird 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
Aus diesen Experimenten können wir ersehen, dass die Sperre in Linux für jeden der Fälle aufgehoben wird, mit denen Sie sich befasst haben.
Wird für jedes Skript auch eine Perl-Instanz ausgeführt, damit klar ist, welches Skript abgestürzt / gestoppt wurde, ohne die Sperre aufzuheben?
Ja, Perl 5 hat einen perl
prozess pro Skript.Auch wenn Sie gabeln, bekommt das Kind seine eigene perl
Prozess.Threading bietet keine separate perl
Prozess.
Beachten:wenn ein übergeordneter Prozess eine Sperre erhält und diese vor dem Sperren nicht aufgibt, hat das Kind dieselbe Sperre, auch wenn der übergeordnete Prozess beendet wird.
Andere Tipps
Wenn das Programm ausgeht, veröffentlicht das Betriebssystem automatisch alle vom Programm erworbenen Schlösser und schließt alle vom Programm geöffneten Dateien.