Calocybe: Perl-Prozesse synchronisieren - oder: Wie baue ich einen Counter?

Beitrag lesen

Hallo auch!

Die von mir verwendete Variante schaut doch ziemlich ähnlich aus - aber nur fast. Bei meinen Überlegungen kam mal so die Frage auf, was denn nun passiert, wenn zwei Prozesse gleichzeitig sehen, daß die *.flock Datei NICHT existier. In diesem Falle würden beide gleichzeitig davon ausgehen, die gesperrte Datei nutzen zu können ...

Ja, habe ich mir auch schon gedacht, haette es aber vorruebergehend in Kauf genommen. Je schneller der Server-Rechner ist (unserer ist immerhin ein Double-Prozessor-System der 6. Generation), um so schneller sollte auch die Abfragerei erledigt sein. Und um so unwahrscheinlicher ist es, dass sich zwei Prozesse genau an dieser Stelle in die Quere kommen.

Wie aber kann ich sicherstellen, daß nur ein Prozess zur Zeit eine flock-Datei anlegt??? Oder allgemeiner gesagt - nur ein Prozess soll den Status auf locked ändern können.

Meine Idee war nun, daß das löschen einer Datei nur einmal (korrekt) auftreten kann.

Ja. Wirklich sicher kann man nur auf Betriebssystemebene synchronisieren.

Die Perl-eigene Funktion zum löschen von Dateien (unlink) gibt glücklicherweise zurück, wieviele der angegebenen Dateien gelöscht wurden! Die geänderte Variante würde also ungefähr wie folgt ausschauen:
1.) Vor dem Lesen der Datei $filename prüfst Du
    while (!-e "$filename.noflock" && $flockcount < 5000) { $flockcount++; }
2.) Vor dem Schreiben der Datei $filename löscht Du $filename.noflock
    if (unlock("$filename.noflock"))
    {
        [...]
    }
3.) Nach dem Schließen der Datei $filename führst Du system("touch $filename.noflock") aus.

Hey super! Sieht gut aus! Natuerlich meinst Du bei 2.)  if (unlink(...)).  Und touch gibt es nur unter UNIX (siehe dazu meine Funktion weiter unten).

So ähnlich jedenfalls. Man sollte hier natürloch noch den Fall abfangen, daß die Datei nicht gelöscht werden konnte. In diesem Falle könnte man z.B. einfach wieder von vorne anfangen.

Man koennte nicht, man sollte. Aber nicht immer wieder, sondern nur eine max. Anzahl oft.

Zum Schluß noch eine Anmerkung: Das warten, welches Cheatah hier einsetzt ist ziemlich aktiv (busy waiting). hier sollte man wohl ein sleep mit in die Schleife setzen, so daß man das Heft regelmäßig an das Betriebssystem abgibt ...

Ja, leider ist die kleinste Aufloesung von Sleep allerdings 1 Sekunde. Naja, dass muessen wir wohl in Kauf nehmen.

Gute Moeglichkeit, ich habe jedoch in die Richtung flock() weiterexperimentiert. Dabei bin ich im Moment so weit:

sub GetCounterBaseControl() {
    my $i;

if (! -e $counterbase) {
        open(CBASE, ">$counterbase");
        close(CBASE);
    }

report "--Tryin' to open!\n";
    for ($i=0; (!open(CBASE, "+<$counterbase") && ($i < $cTIMEOUT)); $i++) { sleep(1) }
    abort() unless ($i < $cTIMEOUT);

report "--Tryin' to lock!\n";
    for ($i=0; (!flock(CBASE, $cFLOCK_EXCLUSIVE|$cFLOCK_NOBLOCK) && ($i < $cTIMEOUT)); $i++) { sleep(1) }
}

$counterbase ist der Dateiname, report() ist eine verkappte print()-Funktion, abort() tut so aehnlich wie die (da ;-)), $cXXX sind selbstdefinierte "Konstanten".
Ich habe zwei Prozesse aufeinanderrennen lassen, indem ich den einen gestartet habe, die Datei habe locken lassen, dann ein sleep(5), den anderen gestartet. Ergebnis: Der zweite Prozess fuehrt das open() durch (davor hatte Cheatah gewarnt!), die TimeOut-Schleife ist dort also sinnlos, aber vor dem Versuch, die Datei zu flocken, haelt er an, bis der erste die Datei wieder freigibt. Also Cheatah: Deine Warnung ist berechtigt. Halten sich aber alle zugreifenden Prozesse an ein gemeinsames Protokoll (das heisst hier "unbedingt flock mit Parameter $cFLOCK_EXCLUSIVE =$LOCK_EX = 2; durchfuehren"), bekommt man die Sache in den Griff.
Die ersten Zeilen der Funktion legen die Datei an, falls sie noch nicht existiert (macht also dasselbe wie touch). Dort tritt natuerlich dasselbe Synchronisierungsproblem auf, das Du mit Deiner Methode gerade vermieden hast. Aber wenn die Counterdatei schon existiert, was sie ja normalerweise tut, ist das auch egal.

Danke fuer Eure Mithilfe, habe einiges gelernt!
Calocybe