Quais comandos Unix podem ser usados como um semáforo / bloqueio?

33

Eu quero executar vários scripts de shell Bash em paralelo. No entanto, quero evitar condições de corrida. Quais comandos Unix são verdadeiramente atômicos que eu poderia usar para essa finalidade, e como posso usá-los?

    
por Larry Wang 10.08.2010 / 21:59

7 respostas

30

Se lockfile não estiver instalado no seu sistema, então mkdir fará o trabalho: é uma operação atômica, e falha se o diretório já existe (contanto que você não adicione a linha de comando -p interruptor).

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"
}
    
por 11.08.2010 / 14:14
25

flock(1)

#!/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

Isso garante que o código entre "(" e ")" seja executado apenas por um processo por vez e que o processo espere por um bloqueio por muito tempo.

    
por 11.08.2010 / 15:41
10

lockfile (1) parece um bom candidato, mas tome cuidado, pois ele faz parte do pacote procmail , que talvez você não tenha instalado na sua máquina ainda. É 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 têm e o outro está disponível.

Usar é simples:

#!/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

As opções que dei permitem repetir uma vez por segundo por até 15 segundos. Solte o sinalizador "-r" se quiser que ele espere para sempre.

    
por 10.08.2010 / 23:04
5

A chamada do sistema mkdir() é atômica nos sistemas de arquivos POSIX. Portanto, usar o comando mkdir de tal forma que envolva exatamente uma chamada para mkdir() atingiria seu objetivo. (IOW, não use mkdir -p ). O desbloqueio correspondente é rmdir , claro.

Emptor de advertência: mkdir() pode não ser atômico em sistemas de arquivos de rede.

    
por 11.08.2010 / 17:15
3

Talvez o comando lockfile faça o que você precisa.

lockfile ~/.config/mylockfile.lock
.....
rm -f important.lock
    
por 10.08.2010 / 22:05
1

Se você estiver apenas usando o Unix, use fifos. Você pode escrever registros de trabalho no fifo e ter processos lidos a partir desse arquivo e seus leitores bloquearão os fifos.

Os arquivos de bloqueio estão ok, mas para o que você descreve eu iria com fifos

    
por 02.09.2014 / 20:54
0

Como postado aqui: " Corrigir o bloqueio em scripts de shell? ", usando a ferramenta FLOM (Free LOck Manager) , a serialização de comandos e shell scripts torna-se tão fácil quanto rodar

flom -- command_to_serialize

O FLOM permite que você implemente casos de uso mais sofisticados (bloqueio distribuído, leitores / gravadores, recursos numéricos, etc ...) como explicado aqui: link

    
por 24.04.2014 / 22:43