Voglio eseguire più script shell Bash in parallelo. Tuttavia, voglio evitare le condizioni di gara. Quali comandi Unix sono veramente atomici che potrei usare per questo scopo e come posso usarli?
Voglio eseguire più script shell Bash in parallelo. Tuttavia, voglio evitare le condizioni di gara. Quali comandi Unix sono veramente atomici che potrei usare per questo scopo e come posso usarli?
Risposte:
Se lockfile
non è installato sul tuo sistema, allora mkdir
farà il lavoro: si tratta di un'operazione atomica e fallisce se la directory esiste già (a patto di non aggiungere l'opzione della -p
riga di comando).
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
Ciò garantisce che il codice tra "(" e ")" venga eseguito solo da un processo alla volta e che il processo attenda un blocco troppo a lungo.
lockf(1)
.
lockf(1)
non funziona nel modo usato in questo esempio, però. Non può accettare un numero descrittore di file come argomento.
lockfile (1) sembra un buon candidato, anche se attenzione che fa parte del pacchetto procmail , che potresti non aver ancora installato sul tuo computer. È un pacchetto abbastanza popolare che dovrebbe essere impacchettato per il tuo sistema se non è ancora installato. Tre dei quattro sistemi che ho controllato ce l'hanno e l'altro ce l'ha a disposizione.
Usarlo è semplice:
#!/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
Le opzioni che ho fornito lo fanno riprovare una volta al secondo per un massimo di 15 secondi. Rilascia il flag "-r" se vuoi che aspetti per sempre.
La chiamata di sistema mkdir()
è atomica sui filesystem POSIX. Quindi, usare il mkdir
comando in modo tale da comportare esattamente una chiamata per mkdir()
raggiungere il tuo scopo. (IOW, non usare mkdir -p
). Lo sblocco corrispondente è rmdir
ovviamente.
Caveat emptor: mkdir()
potrebbe non essere atomico sui filesystem di rete.
rmdir
quindi anche atomico?
Forse il comando lockfile farà quello che ti serve.
lockfile ~/.config/mylockfile.lock
.....
rm -f important.lock
Se stai utilizzando Unix, usa fifos. È possibile scrivere record di lavoro sul Fifo e far leggere i processi da questo file e i lettori lo bloccheranno.
I file di blocco sono ok, ma per quello che descrivi andrei con FIFOS
Come pubblicato qui: " Blocco corretto negli script di shell? ", Utilizzando lo strumento FLOM (Free LOck Manager) , serializzare i comandi e gli script di shell diventa facile come eseguire
flom -- command_to_serialize
FLOM ti consente di implementare casi d'uso più sofisticati (blocco distribuito, lettori / scrittori, risorse numeriche, ecc ...) come spiegato qui: http://sourceforge.net/p/flom/wiki/FLOM%20by%20examples/
make(1)
di prendere il controllo? (vale a dire,make -j 9
se hai 8 core)? Ciò ha l'ulteriore vantaggio del lavoro interlacciato con granularità più fine.