Quais comandos do Unix podem ser usados como um semáforo / bloqueio?
34
Eu quero executar vários scripts de shell Bash em paralelo. No entanto, quero evitar as condições da corrida. Quais comandos do Unix são realmente atômicos que eu poderia usar para esse fim, e como posso usá-los?
O que você está fazendo que requer trabalho paralelo? Você não pode expressar as dependências de uma maneira que permita que um paralelo make(1)assuma o controle? (ou seja, faça um make -j 9se você tiver 8 núcleos)? Isso tem a vantagem adicional de intercalar o trabalho com granularidade mais fina.
Se lockfilenão estiver instalado no seu sistema, ele mkdirfará o trabalho: é uma operação atômica e falhará se o diretório já existir (contanto que você não adicione a -popção da linha 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
Isso garante que o código entre "(" e ")" seja executado apenas por um processo por vez e que o processo aguarde um bloqueio por muito tempo.
Legal, não sabia disso. No entanto, é específico do Linux, aparentemente ...
Riccardo Murri
11
@Riccardo, FreeBSD tem um comando semelhante: lockf(1).
Alex B
lockf(1)não funciona da maneira usada neste exemplo, no entanto. Não pode aceitar um número de descritor de arquivo como argumento.
Charley
11
O lockfile (1) parece um bom candidato, apesar de ser parte do pacote procmail , que talvez você ainda não tenha instalado em sua máquina. É um pacote bastante popular que deve ser empacotado para o seu sistema se ainda não estiver instalado. Três dos quatro sistemas que verifiquei o possuem e o outro está disponível.
Usá-lo é simples:
#!/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
As opções que eu forneci fazem com que tente novamente uma vez por segundo por até 15 segundos. Solte a bandeira "-r" se desejar esperar para sempre.
Esteja ciente de que (de acordo com a página de manual), "Depois que um arquivo é bloqueado, o bloqueio deve ser tocado pelo menos uma vez a cada cinco minutos ou o bloqueio será considerado obsoleto e as tentativas subseqüentes de bloqueio serão bem-sucedidas".
Jay
6
A chamada do sistema mkdir()é atômica nos sistemas de arquivos POSIX. Portanto, usando o mkdircomando de forma a envolver exatamente uma chamada paramkdir() atingir seu objetivo. (IOW, não use mkdir -p). O desbloqueio correspondente é rmdirclaro.
Advertência emptor: mkdir()pode não ser atômico nos sistemas de arquivos da rede.
Se você estiver rodando apenas no Unix, use fifos. Você pode gravar registros de trabalho no fifo e fazer com que os processos sejam lidos neste arquivo, e seus leitores serão bloqueados no fifo.
Os arquivos de bloqueio estão ok, mas pelo que você descreve, eu usaria fifos
make(1)
assuma o controle? (ou seja, faça ummake -j 9
se você tiver 8 núcleos)? Isso tem a vantagem adicional de intercalar o trabalho com granularidade mais fina.Respostas:
Se
lockfile
não estiver instalado no seu sistema, elemkdir
fará o trabalho: é uma operação atômica e falhará se o diretório já existir (contanto que você não adicione a-p
opção da linha de comandos).fonte
flock(1)
Isso garante que o código entre "(" e ")" seja executado apenas por um processo por vez e que o processo aguarde um bloqueio por muito tempo.
fonte
lockf(1)
.lockf(1)
não funciona da maneira usada neste exemplo, no entanto. Não pode aceitar um número de descritor de arquivo como argumento.O lockfile (1) parece um bom candidato, apesar de ser parte do pacote procmail , que talvez você ainda não tenha instalado em sua máquina. É um pacote bastante popular que deve ser empacotado para o seu sistema se ainda não estiver instalado. Três dos quatro sistemas que verifiquei o possuem e o outro está disponível.
Usá-lo é simples:
As opções que eu forneci fazem com que tente novamente uma vez por segundo por até 15 segundos. Solte a bandeira "-r" se desejar esperar para sempre.
fonte
A chamada do sistema
mkdir()
é atômica nos sistemas de arquivos POSIX. Portanto, usando omkdir
comando de forma a envolver exatamente uma chamada paramkdir()
atingir seu objetivo. (IOW, não usemkdir -p
). O desbloqueio correspondente érmdir
claro.Advertência emptor:
mkdir()
pode não ser atômico nos sistemas de arquivos da rede.fonte
rmdir
portanto, também atômica?Talvez o comando lockfile faça o que você precisa.
fonte
Se você estiver rodando apenas no Unix, use fifos. Você pode gravar registros de trabalho no fifo e fazer com que os processos sejam lidos neste arquivo, e seus leitores serão bloqueados no fifo.
Os arquivos de bloqueio estão ok, mas pelo que você descreve, eu usaria fifos
fonte
Como publicado aqui: " Corrigindo o bloqueio em scripts de shell? ", Usando a ferramenta FLOM (Free LOck Manager) , serializar comandos e scripts de shell se torna tão fácil quanto executar
O FLOM permite implementar casos de uso mais sofisticados (bloqueio distribuído, leitores / gravadores, recursos numéricos, etc.), conforme explicado aqui: http://sourceforge.net/p/flom/wiki/FLOM%20by%20examples/
fonte