web-dev-qa-db-fra.com

Quelles commandes UNIX peuvent être utilisées comme un sémaphore / serrure?

Je veux exécuter plusieurs scripts de shell bash en parallèle. Cependant, je veux éviter les conditions de race. Quelles commandes UNIX sont Vraiment atomique que je pourrais utiliser à cette fin et comment puis-je les utiliser?

39
Larry Wang

Si lockfile _ n'est pas installé sur votre système, alors mkdir _ _ _ _ va faire le travail: c'est une opération atomique, et elle échoue si le répertoire existe déjà (tant que vous n'ajoutez pas de -p Commutateur de commande).

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"
}
35
Riccardo Murri

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

Cela garantit que le code entre "(" et ")" ne fonctionne que par un processus à la fois et que le processus attendra une serrure trop longue.

30
Alex B

lockfile (1) ressemble à un bon candidat, mais attention à ce que cela fait partie du package PROCMAIL , que vous n'avez peut-être pas encore installé sur votre appareil. C'est un paquet assez populaire qu'il devrait être emballé pour votre système s'il n'est pas encore installé. Trois des quatre systèmes que j'ai vérifié l'ont, et l'autre l'a disponible.

En utilisant c'est 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

Les options que j'ai données pour réessayer une fois une seconde pendant 15 secondes maximum. Déposez le drapeau "-r" si vous voulez attendre pour toujours.

12
Warren Young

L'appel système mkdir() est atomique sur les systèmes de fichiers POSIX. Ainsi, à l'aide de la commande mkdir _ de telle manière que cela implique exactement un appel à mkdir() obtiendrait votre objectif. (Iow, n'utilisez pas mkdir -p). Le déverrouillage correspondant est rmdir bien sûr.

Cavalier vide: mkdir() peut ne pas être atomique sur les systèmes de fichiers réseau.

7
Hari

Peut-être que la commande Lockfile fera ce dont vous avez besoin.

lockfile ~/.config/mylockfile.lock
.....
rm -f important.lock
3
jacksonh

Si vous ne courez que sur UNIX, utilisez des FIFOs. Vous pouvez écrire des enregistrements de travail à la FIFO et avoir des processus lire à partir de ce fichier et vos lecteurs bloqueront sur les FIFO.

Les fichiers de verrouillage sont ok, mais pour ce que vous décrivez, j'irais avec des FIFOs

1
Chris