Liberação do rebanho em caso de erros?
Pergunta
Imagine o seguinte código Perl (aqui em pseudocódigo):
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
Nesse caso eu não liberaria o bloqueio, pois o script Perl termina na linha 2.Nesse caso, o bloqueio já foi liberado pelo sistema operacional?Ele vê "ei, o script que adquiriu o bloqueio travou" e libera o bloqueio?Ele libera a trava imediatamente?Além disso, há uma instância Perl em execução para cada script, para que fique claro qual script travou/parou sem liberar o bloqueio?
Solução
Nesse caso, o bloqueio já foi liberado pelo sistema operacional?
Ele vê "ei, o script que adquiriu o bloqueio travou" e libera o bloqueio?
Ele libera a trava imediatamente?
Todas essas questões dependem do sistema.Perl 5 não implementa uma função de bloqueio de arquivo, apenas fornece uma interface comum para flock(2)
, fcntl(2)
bloqueio, ou lockf(3)
(dependendo do que está disponível no sistema operacional).Também pode haver uma diferença entre o que acontece quando um programa é encerrado, falha em segmentos ou é eliminado com um sigkill.
Um teste rápido no Linux mostra que um bloqueio é removido em condições normais de saída:
$ 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
Vamos ver o que acontece quando 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.
Para obter um segfault, precisaremos de acesso a C, estou usando Inline
para obtê-la:
$ 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
E finalmente, aqui está o que acontece quando um programa é enviado 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
A partir desses experimentos, podemos ver que o bloqueio é liberado no Linux para cada um dos casos com os quais você estava preocupado.
Além disso, existe uma instância Perl em execução para cada script, para que fique claro qual script travou/parou sem liberar o bloqueio?
Sim, Perl 5 tem um perl
processo por script.Mesmo se você desembolsar, a criança ganha o seu próprio perl
processo.Threading não fornece um separado perl
processo.
Observação:se um processo pai obtiver um bloqueio e não desistir dele antes do bloqueio, o filho terá o mesmo bloqueio mesmo se o pai sair.
Outras dicas
Ao encerrar o programa, o SO libera automaticamente todos os bloqueios adquiridos pelo programa e fecha todos os arquivos abertos pelo programa.