Quiero ejecutar múltiples scripts de shell Bash en paralelo. Sin embargo, quiero evitar las condiciones de carrera. ¿Qué comandos de Unix son realmente atómicos que podría usar para este propósito y cómo puedo usarlos?
Quiero ejecutar múltiples scripts de shell Bash en paralelo. Sin embargo, quiero evitar las condiciones de carrera. ¿Qué comandos de Unix son realmente atómicos que podría usar para este propósito y cómo puedo usarlos?
Respuestas:
Si lockfile
no está instalado en su sistema, entonces mkdir
hará el trabajo: es una operación atómica y falla si el directorio ya existe (siempre y cuando no agregue el -p
interruptor de línea de comandos).
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
Esto garantiza que el código entre "(" y ")" se ejecute solo por un proceso a la vez y que el proceso espere un bloqueo demasiado tiempo.
lockf(1)
.
lockf(1)
Sin embargo, no funciona de la manera utilizada en este ejemplo. No puede tomar un número de descriptor de archivo como argumento.
lockfile (1) parece un buen candidato, aunque tenga en cuenta que es parte del paquete procmail , que es posible que aún no haya instalado en su máquina. Es un paquete suficientemente popular que debería empaquetarse para su sistema si aún no está instalado. Tres de los cuatro sistemas que verifiqué lo tienen, y el otro lo tiene disponible.
Usarlo es simple:
#!/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
Las opciones que he dado hacen que vuelva a intentarlo una vez por segundo durante hasta 15 segundos. Suelta la bandera "-r" si quieres que espere para siempre.
La llamada al sistema mkdir()
es atómica en los sistemas de archivos POSIX. Entonces, usar el mkdir
comando de tal manera que implique exactamente una llamada para mkdir()
lograr su propósito. (IOW, no lo uses mkdir -p
). El desbloqueo correspondiente esrmdir
por supuesto.
Advertencia: es mkdir()
posible que no sea atómico en los sistemas de archivos de red.
rmdir
por lo tanto también atómico?
Tal vez el comando lockfile hará lo que necesita.
lockfile ~/.config/mylockfile.lock
.....
rm -f important.lock
Si solo está ejecutando en Unix, use fifos. Puede escribir registros de trabajo en el Fifo y hacer que los procesos se lean desde este archivo y sus lectores bloquearán en el Fifos.
Los archivos de bloqueo están bien, pero por lo que describe iría con fifos
Como se publica aquí: "¿ Bloqueo correcto en los scripts de shell? ", Utilizando la herramienta FLOM (Free LOck Manager) , la serialización de comandos y scripts de shell se vuelve tan fácil como ejecutar
flom -- command_to_serialize
FLOM le permite implementar casos de uso más sofisticados (bloqueo distribuido, lectores / escritores, recursos numéricos, etc.) como se explica aquí: http://sourceforge.net/p/flom/wiki/FLOM%20by%20examples/
make(1)
haga cargo? (es decir, haz unmake -j 9
si tienes 8 núcleos)? Esto tiene la ventaja adicional de entrelazar el trabajo con una granularidad más fina.