Probleme mit gleichzeitigem Dateizugriff
Jonas
- perl
0 Struppi0 Jonas
0 agapanthus0 Chris
Hallo
Ich habe das Problem, dass wenn viele User eine Seite aufrufen, welche mit Perl erzeugt wird, gewisse Dateien nach einer Weile bzw. bei zu vielen "simultanen" Zugriffen "geleert werden".
Die etwas genauere Beschreibung des Problems:
Bei jedem Seitenaufruf wird im Grunde folgendes ausgeführt (eigentlich werden mehr als nur das $tmp[0]++ ausgeführt, aber der einfachheithalber hier mal nur das).
##################code
#open counter.dat file
fopen(FILE, "<counter.dat");
my @tmp = <FILE>;
fclose(FILE);
$tmp[0]++;
#write counter.dat file back
fopen(FILE, ">counter.dat");
foreach (@tmp) {print FILE "$_\n";}
fclose(FILE);
##################code
Mit folgenden subs:
##################code
$fopen = 2;
$fclose = 8;
$uflock = 1;
sub fopen {
my($fh,$fn) = @_;
if($fn =~ m~/../~) {
eval { perror("OPEN_ERROR"); };
die "\n\nYou MUST use absolute paths.\n\n";
}
open($fh,$fn);
if($uflock) {
flock($fh,$fopen);
seek($fh,0,0);
}
}
sub fclose {
my($fh) = $_[0];
if($uflock) { flock($fh,$fclose); }
close($fh);
}
##################code
Nun ja, wie gesagt wird der Wert dann immer schön hochgezählt, plötzlich ist das Ganze aber dann wieder leer.
Gibt es da eine Möglichkeit. Ich dachte anfangs, mit dem File-Lock hätte ich das Problem gelöst. Scheinbar war dies aber ein Trugschluss...
Gruss und Dank
Jonas
Dein Problem liegt zwischen hier:
fclose(FILE);
$tmp[0]++;
#write counter.dat file back
und hier:
fopen(FILE, ">counter.dat");
in dieser Zeit ist die Datei geschlossen und kann von einem anderen Prozess erneut geöffnet werden.
Du musst die Datei zum lesen und schreiben öffnen, dann Wert lesen, Wert erneuern, Wert schreiben (du musst dann aber den Dateizeiger mit seek neu setzen) und dann erst schliessen.
Struppi.
Hallo
Erstmals danke für alle Inputs!
@Struppi:
Hmm.... du hast recht. Du meinst, dass ich die Datei während des $tmp[0]++ offen lasse und erst dann schliesse? Dann würde der flock "erhalten bleiben" bis alle Operationen an dem File beendet sind, oder?
Gruss
Jonas
Dein Problem liegt zwischen hier:
fclose(FILE);
$tmp[0]++;
#write counter.dat file back
und hier:
fopen(FILE, ">counter.dat");
in dieser Zeit ist die Datei geschlossen und kann von einem anderen Prozess erneut geöffnet werden.
Du musst die Datei zum lesen und schreiben öffnen, dann Wert lesen, Wert erneuern, Wert schreiben (du musst dann aber den Dateizeiger mit seek neu setzen) und dann erst schliessen.
Struppi.
Moin.
Es gibt eine 2. Fehlerquelle:
Dein Perlprozeß ist unterbrechbar durch das Betriebssystem. Wird er nun zw.
if($uflock) { flock($fh,$fclose); }
und
close($fh);
durch einen anderen Prozess, der ebenfalls in Dein File schreibt, unterbrochen, geht das Ergebnis eines Prozesses verloren, das letzte close ($fh) "gewinnt". Laß flock($fh,$fclose) weg, es wird duch close implizit ausgeführt. Damit wird das File wirklich erst "geunlockt", wenn es auch geschrieben wurde.
Gruß Frank
Hallo,
ich kann zwar immer noch kein PERL, aber generell sei gesagt:
wird eine Ressource zum Zwecke der Veränderung belegt, so muss sie bereits _vor_ dem ersten Lesen exclusiv gesperrt werden.
Die Vorgänge des Lesens und des zurückschreibens sind nicht teilbar und müssen komplett durch ein exclusives Lock (entsprechendes Semaphor) geschützt werden.
Damit dieser Schutz greift, muss jeder beteiligte Prozess auf denselben Semaphor zugreifen und kein Prozess darf das vereinbarte Verfahren umgehen. Üblicherweise werden daher die Prozesse der Sperrung von Ressourcen im Betriebssystem gekapselt.
LG
Chris