Wie sperre ich eine Datei (locking)?
Inhalt:
Problem
Du hast einen Webcounter und möchtest den Inhalt um eins hochzählen. Der klassische Fehler ist, die Datei
zu öffnen, den Inhalt auszulesen, die Datei wieder zu schließen, die Datei zum Schreiben öffnen und
den neuen Wert einfügen. In der Zwischenzeit können beliebige Prozesse auf die Datei zugreifen.
Ein damit zusammenhängender Fehler ist es, die Datei beim zweiten mal auch noch mit
open COUNT, '>', 'pfad'
zu öffnen. Dabei wird der Inhalt zerstört,
bevor der lock angelegt werden kann.
Lösung
# konstanten LOCK_EX, SEEK_SET importieren
use Fcntl qw(:seek :flock);
# dateiname
my $counter = "counter";
# Datei zum Lesen und Schreiben öffnen
open my $lock, '+<', $counter
or die "Konnte '$counter' nicht öffnen: $!";
# exklusiv sperren
flock $lock, LOCK_EX;
# counter auslesen
chomp(my $num = <$lock>);
$num++;
# an den anfang der datei springen
seek $lock, 0, SEEK_SET;
# datei auf größe 0 zurücksetzen
truncate $lock, 0;
# neuen wert reinschreiben
print $lock "$num\n";
# schließen
close $lock;
# ---------- ohne kommentare
use Fcntl qw(:seek :flock);
my $counter = "counter";
open my $lock, '+<', $counter
or die "Konnte '$counter' nicht öffnen: $!";
flock $lock, LOCK_EX;
chomp(my $num = <$lock>);
$num++;
seek $lock, 0, SEEK_SET;
truncate $lock, 0;
print $lock "$num\n";
close $lock;
Kurze Liste der Konstanten
LOCK_SH: Shared Lock
Wenn man nur lesen will
LOCK_EX: Exclusiver Lock
Wenn man schreiben (und lesen) will
LOCK_NB: Nicht blockierender Lock
Wird benutzt mit
LOCK_SH oder
LOCK_EX. Gibt sofort ein Ergebnis zurück, anstatt zu warten.
if (flock FILEHANDLE, LOCK_EX | LOCK_NB) {
# prima
}
else {
# kein lock, Plan B
}
LOCK_UN: Lock aufheben
Wird selten gebraucht, da ein Schließen der Daei den Lock automatisch und atomar aufhebt.
Literatur
perldoc -q locking
perldoc perlopentut
perldoc -f seek
perldoc -f truncate
Ergänzungen, Kommentare
Kommentare werden am besten in folgender Form vorgenommen, damit
sie im Inhaltsverzeichnis angezeigt werden (natürlich ohne das <verbatim>):
---+++ Main.??? - 14 Jul 2003 - Betreff