¿Qué comandos de Unix se pueden usar como semáforo / bloqueo?
34
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?
¿Qué haces que requiere trabajo paralelo? ¿No puedes expresar las dependencias de una manera que permita que un paralelo se make(1)haga cargo? (es decir, haz un make -j 9si tienes 8 núcleos)? Esto tiene la ventaja adicional de entrelazar el trabajo con una granularidad más fina.
Si lockfileno está instalado en su sistema, entonces mkdirhará el trabajo: es una operación atómica y falla si el directorio ya existe (siempre y cuando no agregue el -pinterruptor de línea de comandos).
#!/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 10200# 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.
Buena, no lo sabía. Sin embargo, aparentemente es específico de Linux ...
Riccardo Murri
1
@Riccardo, FreeBSD tiene un comando similar: lockf(1).
Alex B
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.
Charley
11
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 Waitingfor 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 1fi
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.
Tenga en cuenta que (de acuerdo con la página de manual), "Una vez que un archivo está bloqueado, el bloqueo debe tocarse al menos una vez cada cinco minutos o el bloqueo se considerará obsoleto y los intentos de bloqueo posteriores tendrán éxito".
Jay
6
La llamada al sistema mkdir()es atómica en los sistemas de archivos POSIX. Entonces, usar el mkdircomando 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.
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
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.Respuestas:
Si
lockfile
no está instalado en su sistema, entoncesmkdir
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).fuente
flock(1)
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.
fuente
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:
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.
fuente
La llamada al sistema
mkdir()
es atómica en los sistemas de archivos POSIX. Entonces, usar elmkdir
comando de tal manera que implique exactamente una llamada paramkdir()
lograr su propósito. (IOW, no lo usesmkdir -p
). El desbloqueo correspondiente esrmdir
por supuesto.Advertencia: es
mkdir()
posible que no sea atómico en los sistemas de archivos de red.fuente
rmdir
por lo tanto también atómico?Tal vez el comando lockfile hará lo que necesita.
fuente
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
fuente
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 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/
fuente