2013-07-17 8 views
16

Ich bin mit flock() für Inter-Prozess namens mutexes (dh einige Verfahren eine Sperre auf „some_name“ entscheiden können, halten, die durch Sperren eine Datei in einem temporären Verzeichnis mit dem Namen implementiert wird „some_name“:flock(): Entfernen der gesperrten Datei ohne Racebedingung?

lockfile = "/tmp/some_name.lock"; 
fd = open(lockfile, O_CREAT); 
flock(fd, LOCK_EX); 

do_something(); 

unlink(lockfile); 
flock(fd, LOCK_UN); 

die Sperrdatei irgendwann entfernt werden soll, um zu vermeiden, Hunderte von Dateien des temporäre Verzeichnis füllt

Allerdings gibt es eine offensichtliche race-Bedingung in diesem Code, beispielsweise mit Verfahren A, B und C:.

A opens file 
A locks file 
B opens file 
A unlinks file 
A unlocks file 
B locks file (B holds a lock on the deleted file) 
C opens file (a new file one is created) 
C locks file (two processes hold the same named mutex !) 

Ist t hier eine Möglichkeit, die Sperrdatei irgendwann zu entfernen, ohne diese Race Condition einzuführen?

+2

Problem ist, dass Sie versuchen, eine feinkörnige Sperrstrategie zu implementieren (Dateien stellen Ressourcen dar), aber Sie haben Konflikte auf einer freigegebenen grobkörnigen Ressource (dem Dateisystem). Sie benötigen entweder eine globale Sperre für das Sperrdateiverzeichnis, bevor Sie Ihre feinkörnigen Sperren aktualisieren, oder Sie ändern Ihre Sperrstrategie vollständig neu. – jxh

+0

Können Sie Ihr Bedürfnis ausarbeiten? ZB warum benutzen die Programme nicht einen bekannten Dateinamen, wenn sie alle dieselbe konzeptionelle Ressource sperren? –

Antwort

20

Sorry, wenn ich auf eine tote Frage antworten:

Nach dem Sperren von Dateien, eine weitere Kopie davon öffnen, fstat beiden Kopien und überprüfen Sie die Inode-Nummer, wie folgt aus:

lockfile = "/tmp/some_name.lock"; 

    while(1) { 
     fd = open(lockfile, O_CREAT); 
     flock(fd, LOCK_EX); 

     fstat(fd, &st0); 
     stat(lockfile, &st1); 
     if(st0.st_ino == st1.st_ino) break; 

     close(fd); 
    } 

    do_something(); 

    unlink(lockfile); 
    flock(fd, LOCK_UN); 

Dies verhindert, dass die Race-Bedingung, denn wenn ein Programm eine Sperre für eine Datei hält, die sich noch im Dateisystem befindet, hat jedes andere Programm, das eine Restdatei hat, eine falsche Inode-Nummer.

erweisen ich es tatsächlich in der Zustandsmaschine Modell, die folgenden Eigenschaften verwenden:

Wenn P_i einen Descriptor auf dem Dateisystem dann kein anderer Prozess im kritischen Abschnitt gesperrt hat, ist.

Wenn P_i nach dem Stat mit der rechten Inode oder im kritischen Abschnitt ist, hat es den Deskriptor im Dateisystem gesperrt.

+0

Große Antwort, danke! – arnaud576875

+1

Sie können die Datei entsperren, nachdem sie nicht verknüpft und geschlossen wurde? Handbuch sagt, dass Herde "Bewerben oder entfernen Sie eine beratende Sperre für die offene Datei von fd angegeben". – sheerun

+1

Solltest du nicht auch das fd am Ende schließen, um ein Leck zu verhindern? –

3

Wenn Sie diese Dateien nur zum Sperren verwenden und nicht tatsächlich an sie schreiben, empfehle ich Ihnen, die Existenz des Verzeichniseintrags selbst als Hinweis auf eine gehaltene Sperre zu behandeln und die Verwendung von flock insgesamt zu vermeiden.

Dazu müssen Sie eine Operation erstellen, die einen Verzeichniseintrag erstellt und einen Fehler meldet, falls dieser bereits existiert. Unter Linux und mit meisten Dateisystemen, die O_EXCL an open übergeben wird dafür arbeiten. Aber einige Plattformen und einige Dateisysteme (insbesondere ältere NFS) unterstützen dies nicht. Die man page for open schlägt daher eine Alternative:

Portable Programme, die Atom-Datei Sperren einer Sperrdatei mit durchführen möchten, und müssen Vertrauen auf NFS-Unterstützung zu vermeiden, für O_EXCL kann eine eindeutige Datei auf demselben Dateisystem erstellen (zB Hostnamen und PID einbeziehen, und verwenden Sie link (2), um eine Verbindung zur Sperrdatei herzustellen. Wenn link (2) 0 zurückgibt, ist die Sperre erfolgreich. Andernfalls verwenden Sie stat (2) für die eindeutige Datei, um zu überprüfen, ob die Anzahl der Verknüpfungen auf 2 erhöht wurde. In diesem Fall ist die Sperre ebenfalls erfolgreich.

Das sieht also nach einem Schließschema aus, das offiziell dokumentiert ist und daher ein gewisses Maß an Unterstützung und Best-Practice-Vorschlägen anzeigt. Aber ich habe auch andere Ansätze gesehen. bzr verwendet zum Beispiel Verzeichnisse anstelle von Symlinks an den meisten Orten. Zitiert aus its source code:

Ein Schloss wird von einem Verzeichnis eines bestimmten Namens auf der Platte vertreten, eine Informationsdatei enthält. Eine Sperre wird durch Umbenennen eines temporären Verzeichnisses an Ort und Stelle vorgenommen. Wir benutzen temporäre Verzeichnisse, weil für alle bekannten Transporte und Dateisysteme wir glauben, dass genau ein Versuch, die Sperre zu erlangen, erfolgreich sein wird und die anderen fehlschlagen werden. (. Dateien wird nicht, weil einige Dateisysteme oder transportiert nur haben Umbenennungs-und-überschreiben, ist es schwer zu sagen, macht, wer gewonnen hat)

Ein Nachteil der obigen Ansätze ist, dass sie nicht blockiert werden: Ein fehlgeschlagener Sperrversuch wird zu einem Fehler führen, aber nicht warten, bis die Sperre verfügbar ist. Sie werden nach der Sperre fragen müssen, was im Hinblick auf Sperrkonflikte problematisch sein könnte. In diesem Fall möchten Sie möglicherweise von Ihrem Dateisystem-basierten Ansatz abweichen und stattdessen Implementierungen von Drittanbietern verwenden. Aber allgemeine Fragen, wie ipc Mutexe zu tun haben, wurden bereits gefragt, also schlage ich Ihnen search for [ipc] [mutex] vor und werfen Sie einen Blick auf die Ergebnisse, insbesondere this one.Übrigens könnten diese Tags auch für Ihren Post nützlich sein.

+5

Das Problem dieses Ansatzes ist, dass wenn ein Prozess stirbt, während er ein Schloss hält, es keinen vernünftigen Weg gibt, das Schloss automatisch zu ernten. Im Gegensatz dazu bleibt bei dem "Flock" -Ansatz, wenn ein Prozess während des Haltens der Sperre abstirbt, die Datei auf dem Dateisystem, aber sie wird nicht mehr "geflockt"; Andere Prozesse können jetzt die Sperre erwerben. – davidg

+0

@davidg: Das ist ein gültiger Punkt. Einige Implementierungen schreiben einen Zeitstempel und/oder die PID des Sperrprozesses in die Datei, die mit dem Sperrdateinamen oder mit einer bekannten Datei im Sperrverzeichnis verknüpft wird. Auf diese Weise können Sie überprüfen, ob ein Prozess mit dieser ID noch aktiv ist, und Sie können Sperren nach einer bestimmten Zeit ablaufen lassen. – MvG

Verwandte Themen