GNU / Linux-Flock-Befehl: Mehrere Sperren werden atomar ausgeführt

819
Renaud Pacalet

Ich habe mehrere Befehle, die ich parallel ausführen möchte, aber nur dann, wenn in den Ressourcen, auf die sie zugreifen, keine Konflikte auftreten. Also entschied ich mich zu benutzen flock. Jeder Befehl muss eine exklusive (Schreib-) Sperre und mehrere gemeinsam genutzte (Lese-) Sperren annehmen. Da flockmehrere Sperren nicht unterstützt werden, dachte ich naiv:

flock -x a flock -s b flock -s c ... <command> 

würde funktionieren. Ich habe schnell herausgefunden, dass bei diesem Ansatz Rassenbedingungen herrschen, da die Sperren nicht atomar sind. Beim Start:

flock -x a flock -s b <command1> & flock -x b flock -s a <command2> & 

Es kann sein, dass die beiden exklusiven Sperren gleichzeitig ausgeführt werden und die beiden Befehle in einen Deadlock gehen, da sie ihre gemeinsam genutzten Sperren nicht annehmen können.

Gibt es eine Problemumgehung? Sind es andere Sperrdienstprogramme, die mehrere Sperren auf atomarer Weise unterstützen? Oder sollte ich eine eigene erstellen, die versucht, die Sperren zu übernehmen, sie nach einem Timeout wieder freizugeben, falls dies fehlschlägt, und nach einer zufälligen Verzögerung erneut versucht? Oder etwas ähnliches?

Aktualisieren Sie anscheinend das Problem durch Sortieren der Sperren nach Namen:

flock -x a flock -s b <command1> & flock -s a flock -x b <command2> & 

aber wie robust ist das? Verhindert es in allen Situationen Deadlocks mit einer beliebigen Anzahl von Befehlen, einer Anzahl von Sperren, Sperrennamen und Sperrensätzen pro Befehl (immer noch mit der Einschränkung, dass es genau eine ausschließliche Sperre pro Befehl gibt)?

1
Es sieht für mich aus`und``von Ihren Beispielen wird nie parallel laufen. Eine gemeinsam genutzte Sperre verhindert die exklusive Sperre für dieselbe Datei. Eine exklusive Sperre verhindert die Sperrung derselben Datei. Sie können diese Befehle also einfach nacheinander ausführen. Stellen Sie sicher, dass Ihr tatsächliches Problem nicht auf die gleiche Weise fehlerhaft ist, andernfalls ist die gesamte "parallele" Idee sinnlos. Wenn es genau eine exklusive Sperre pro Befehl gibt, dann ``kann parallel mit` laufen`Wenn` A` die exklusive Datei von `B` überhaupt nicht sperrt und` B` die exklusive Datei von `A` überhaupt nicht. Kamil Maciorowski vor 6 Jahren 0
@ KamilMaciorowski Ich bin nicht sicher, ob ich deinen ersten Kommentar verstehe. Ich weiß, dass in meinen Beispielen die von mir gezeigten Befehle nicht parallel ausgeführt werden. Im ersten Beispiel, weil es einen Deadlock gibt, und im zweiten, weil das Umordnen der Sperren den Deadlock verhindert, indem eine sequentielle Ausführung erzwungen wird. Sie waren nur Beispiele für Fälle, in denen Dinge schief gehen. Habe ich etwas verpasst? Renaud Pacalet vor 6 Jahren 0
Ich wollte nur sicherstellen, dass Sie wissen, dass die Beispiele niemals von der parallelen Ausführung profitieren. Wenn das eigentliche Problem ähnlich fehlerhaft war (jeder Befehl sperrt * jede * wichtige Datei), können Sie alles nacheinander und (wahrscheinlich) ohne "Flock" ausführen. Kamil Maciorowski vor 6 Jahren 0

2 Antworten auf die Frage

1
Kamil Maciorowski

Dies ist das Problem der Essensphilosophen . Durch das Sortieren der Sperren implementieren Sie eine Lösung für die Ressourcenhierarchie .

Während die Lösung für Ressourcenhierarchien Deadlocks vermeidet, ist dies nicht immer praktikabel, insbesondere wenn die Liste der benötigten Ressourcen nicht vollständig bekannt ist.

Es sieht so aus, als wäre es robust, wenn nur Sie Ihre Ressourcen sortieren und dabei bleiben können.


Eine Problemumgehung kann darin bestehen, nicht flockunbegrenzt warten zu lassen, dann eine Logik hinzuzufügen, um Fälle zu erkennen, wenn das Programm beendet wurde, weil es eine Datei nicht sperren konnte, und die gesamte Aufgabe beispielsweise nach einer zufälligen Zeit wiederholt wird.

In man flockeinem kann man sehen:

-n, --nb, --nonblock
Ausfallen (mit einem Exit - Code 1) anstatt warten, wenn die Sperre nicht sofort erworben werden kann.

-w, --wait, --timeout seconds
Ausfallen (mit einem Exit - Code 1), wenn die Sperre nicht innerhalb von Sekunden Sekunden erfaßt werden. Dezimale gebrochene Werte sind zulässig.

Das Problem ist: Ein möglicher Exit-Code von 1kann von jedem flockoder von dem zugrundeliegenden Befehl kommen. Wenn Ihr flockTräger -Eeinen benutzerdefinierten Exit - Code angeben - es vielleicht verwenden.

Dies ist ein einfaches Beispiel für den Ansatz:

while ! flock -n -x file <command> ; do sleep $(($RANDOM%5)) ; done 

Sie können mehrere flock-s verwenden. Wenn einer von ihnen die Datei nicht sperren kann, werden alle Sperren aufgehoben und die gesamte Zeile wartet auf sleep, nicht auf flock; Zu diesem Zeitpunkt wird keine weitere, parallel ausgeführte Zeile blockiert.

Ja, danke, das ist die Lösung, die ich in meiner Frage vorgeschlagen habe. Aber ich habe etwas Besseres erwartet, wenn es existiert. Renaud Pacalet vor 6 Jahren 0
Sie haben recht, Kamil, es sieht aus wie die Lösung der Ressourcenhierarchie des Problems der Essensphilosophen ... Abgesehen von den gemeinsamen Sperren und der exklusiven exklusiven Sperre pro Job. Ich würde gerne wissen, ob sich etwas ändert oder nicht. Renaud Pacalet vor 6 Jahren 0
1
AFH

Als ich an der Echtzeitprogrammierung beteiligt war, verabscheute ich immer Verzögerungs- / Wiederholungslösungen, obwohl diese oft einfacher zu programmieren sind.

Der Schlüssel zum Vermeiden eines Deadlocks besteht darin, niemals eine zweite Sperre in die Warteschlange zu stellen, während eine Sperre gehalten wird. Verwenden Sie also für drei Dateien Folgendes: -

while true do flock -x a flock -nE 101 -s b flock -nE 102 c Command case $? in 101) flock -s b;; 102) flock -s c;; *) break;; done 

Die Rückgabewerte, die in flock -Everwendet werden, müssen Werte sein, die vom Befehl nie zurückgegeben werden. Wenn einer dieser Werte zurückgegeben wird, wird das Skript für die gesperrte Ressource in die Warteschlange gestellt und der ursprüngliche Aufruf wiederholt.

Im Prinzip spielt es keine Rolle, in welcher Reihenfolge die Sperren angefordert werden, es kann jedoch die Codierung vereinfachen, um zuerst die exklusive Sperre anzufordern.

Es gibt eine effizientere Lösung, die das Aufheben der Sperre in der Warteschlange unmittelbar vor der erneuten Anforderung verhindert: Erstellen Sie die Laufzeichenfolge jedes Mal neu, und erstellen Sie sie bei jedem nicht blockierenden Fehler neu.

flock -s b flock -nE 102 flock -nE 100 -x a c Command 

(Natürlich wird ein zusätzlicher Fall für 100)benötigt.)

In einem allgemeineren Fall werden die Sperrdateien an eine Funktion übergeben, die die Dateien in einem Array speichert und die Laufzeichenfolge (die Folge von flocks) erstellt und die Parameterarithmetik verwendet, um die Datei auszuwählen, in die die Warteschlange gestellt werden soll, wenn die nicht blockierenden Sperren erfolgen Scheitern.

Die Codierung für beide wird komplex sein, insbesondere wenn eingebettete Leerzeichen in Commandund die zugehörigen Parameter berücksichtigt werden. Daher habe ich den obigen einfachen Fall gewählt, um das Prinzip zu veranschaulichen, das bei der fortgeschrittenen Codierung für den allgemeinen Fall verloren gehen würde.

In Bezug auf die Gäste bezieht sich der Algorithmus darauf, die linke Gabel aufzuheben, falls verfügbar. ansonsten warte darauf. Wenn auch die rechte Gabel verfügbar ist, nehmen Sie sie mit und essen Sie; Wenn nicht, legen Sie die linke Gabel wieder ab und warten Sie auf die rechte. Bei Dinern könnte es eine Wettlaufsituation geben, bei der jeder die linke Gabel genau zur gleichen Zeit aufhebt. In der Datenverarbeitung kann dies nicht passieren, da zu jedem Zeitpunkt nur eine Sache passieren kann (dies gilt nicht für ein Netzwerk mit mehreren Computern, gilt jedoch für eine Multi-Core-CPU, es sei denn, die Hintergrundaufgaben werden explizit verschiedenen Kernen zugewiesen.) . AFH vor 6 Jahren 0