Ich möchte mehrere Bash-Shell-Skripte gleichzeitig ausführen. Ich möchte jedoch Rennbedingungen vermeiden. Welche Unix-Befehle sind wirklich atomar, die ich für diesen Zweck verwenden könnte, und wie kann ich sie verwenden?
Ich möchte mehrere Bash-Shell-Skripte gleichzeitig ausführen. Ich möchte jedoch Rennbedingungen vermeiden. Welche Unix-Befehle sind wirklich atomar, die ich für diesen Zweck verwenden könnte, und wie kann ich sie verwenden?
Antworten:
Wenn lockfile
es nicht auf Ihrem System installiert ist, mkdir
erledigt es die Arbeit: Es ist eine atomare Operation und es schlägt fehl, wenn das Verzeichnis bereits vorhanden ist (solange Sie den -p
Befehlszeilenschalter nicht hinzufügen ).
create_lock_or_wait () {
path="$1"
wait_time="${2:-10}"
while true; do
if mkdir "${path}.lock.d"; then
break;
fi
sleep $wait_time
done
}
remove_lock () {
path="$1"
rmdir "${path}.lock.d"
}
#!/bin/bash
# Makes sure we exit if flock fails.
set -e
(
# Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
flock -x -w 10 200
# Do stuff
) 200>/var/lock/.myscript.exclusivelock
Dadurch wird sichergestellt, dass der Code zwischen "(" und ")" jeweils nur von einem Prozess ausgeführt wird und der Prozess zu lange auf eine Sperre wartet.
lockf(1)
.
lockf(1)
funktioniert jedoch nicht so wie in diesem Beispiel. Eine Dateideskriptornummer kann nicht als Argument verwendet werden.
lockfile (1) sieht aus wie ein guter Kandidat, obwohl es Teil des procmail- Pakets ist, das Sie möglicherweise noch nicht auf Ihrem Computer installiert haben. Es ist ein beliebtes Paket, das für Ihr System gepackt werden sollte, wenn es noch nicht installiert ist. Drei der vier von mir überprüften Systeme haben es und das andere hat es zur Verfügung.
Die Benutzung ist einfach:
#!/bin/sh
LOCKFILE=$HOME/.myscript/lock
mkdir -p `dirname $LOCKFILE`
echo Waiting for lock $LOCKFILE...
if lockfile -1 -r15 $LOCKFILE
then
# Do protected stuff here
echo Doing protected stuff...
# Then, afterward, clean up so another instance of this script can run
rm -f $LOCKFILE
else
echo "Failed to acquire lock! lockfile(1) returned $?"
exit 1
fi
Die Optionen, die ich angegeben habe, lassen es bis zu 15 Sekunden lang einmal pro Sekunde wiederholen. Löschen Sie das Flag "-r", wenn Sie möchten, dass es für immer wartet.
Der Systemaufruf mkdir()
ist bei POSIX-Dateisystemen atomar. Verwenden Sie den mkdir
Befehl also so, dass genau ein Aufruf mkdir()
erforderlich ist, um Ihren Zweck zu erreichen. (IOW, nicht benutzen mkdir -p
). Das entsprechende Entsperren ist rmdir
natürlich.
Vorsichtsmaßnahme: mkdir()
Möglicherweise sind Netzwerk-Dateisysteme nicht atomar.
rmdir
also auch atom?
Vielleicht wird der Befehl lockfile das tun, was Sie brauchen.
lockfile ~/.config/mylockfile.lock
.....
rm -f important.lock
Wenn Sie nur unter Unix arbeiten, verwenden Sie fifos. Sie können Arbeitsdatensätze in das Fifo schreiben und Prozesse aus dieser Datei lesen lassen, und Ihre Leser blockieren die Fifos.
Sperrdateien sind in Ordnung, aber für das, was Sie beschreiben, würde ich mit Fifos gehen
Wie hier beschrieben: " Korrektes Sperren in Shell-Skripten? " Mit dem FLOM-Tool (Free LOck Manager) wird das Serialisieren von Befehlen und Shell-Skripten so einfach wie das Ausführen
flom -- command_to_serialize
Mit FLOM können Sie komplexere Anwendungsfälle (verteiltes Sperren, Lese- / Schreibvorgänge, numerische Ressourcen usw.) implementieren, wie hier erläutert: http://sourceforge.net/p/flom/wiki/FLOM%20by%20examples/
make(1)
übernehmen kann? (also amake -j 9
wenn du 8 Kerne hast)? Dies hat den zusätzlichen Vorteil, dass Interleaving-Arbeiten mit einer feineren Granularität ausgeführt werden.