Quelles commandes Unix peuvent être utilisées en tant que sémaphore / verrou?
34
Je veux exécuter plusieurs scripts shell Bash en parallèle. Cependant, je veux éviter les conditions de course. Quelles commandes Unix sont vraiment atomiques que je pourrais utiliser à cette fin et comment puis-je les utiliser?
Que faites-vous qui nécessite un travail parallèle? Ne pouvez-vous pas exprimer les dépendances de manière à permettre à un parallèle make(1)de prendre le relais? (c.-à-d. make -j 9si vous avez 8 cœurs)? Cela présente l’avantage supplémentaire d’entrelacer les travaux avec une granularité plus fine.
Si lockfilen'est pas installé sur votre système, mkdirle travail sera alors effectué: il s'agira d'une opération atomique qui échouera si le répertoire existe déjà (tant que vous n'ajoutez pas le -pcommutateur de ligne de commande).
#!/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
Cela garantit que le code entre "(" et ")" est exécuté uniquement par un processus à la fois et qu'il attend trop longtemps le verrouillage.
Belle, je ne savais pas à ce sujet. Cependant, il est apparemment spécifique à Linux ...
Riccardo Murri
1
@Riccardo, FreeBSD dispose d' une commande similaire: lockf(1).
Alex B
lockf(1)ne fonctionne pas de la manière utilisée dans cet exemple, cependant. Il ne peut pas prendre un numéro de descripteur de fichier en argument.
Charley
11
lockfile (1) semble être un bon candidat, mais sachez que cela fait partie du paquet procmail , que vous n'avez peut-être pas encore installé sur votre ordinateur. C'est un paquet assez populaire pour qu'il soit packagé pour votre système s'il n'est pas encore installé. Trois des quatre systèmes que j'ai vérifiés l'ont et l'autre le dispose.
Son utilisation est 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
Les options que je vous ai données permettent de réessayer une fois par seconde pendant 15 secondes maximum. Supprimez l'indicateur "-r" si vous souhaitez attendre indéfiniment.
Sachez que (selon la page de manuel), "Une fois qu'un fichier est verrouillé, le verrou doit être touché au moins une fois toutes les cinq minutes, sinon le verrou sera considéré comme périmé et les tentatives de verrouillage suivantes aboutiront."
Jay
6
L'appel système mkdir()est atomique sur les systèmes de fichiers POSIX. Donc, en utilisant la mkdircommande de telle sorte qu'elle implique exactement un appel, vous mkdir()atteindriez votre but. (IOW, ne pas utiliser mkdir -p). Le déverrouillage correspondant est rmdirbien sûr.
Caveat emptor: mkdir()pourrait ne pas être atomique sur les systèmes de fichiers du réseau.
Si vous utilisez uniquement Unix, utilisez fifos. Vous pouvez écrire des enregistrements de travail dans le fifo et faire en sorte que les processus soient lus à partir de ce fichier. Vos lecteurs bloquent alors sur le fifo.
Les fichiers de verrouillage sont ok, mais pour ce que vous décrivez, j'irais avec fifos
make(1)
de prendre le relais? (c.-à-d.make -j 9
si vous avez 8 cœurs)? Cela présente l’avantage supplémentaire d’entrelacer les travaux avec une granularité plus fine.Réponses:
Si
lockfile
n'est pas installé sur votre système,mkdir
le travail sera alors effectué: il s'agira d'une opération atomique qui échouera si le répertoire existe déjà (tant que vous n'ajoutez pas le-p
commutateur de ligne de commande).la source
flock(1)
Cela garantit que le code entre "(" et ")" est exécuté uniquement par un processus à la fois et qu'il attend trop longtemps le verrouillage.
la source
lockf(1)
.lockf(1)
ne fonctionne pas de la manière utilisée dans cet exemple, cependant. Il ne peut pas prendre un numéro de descripteur de fichier en argument.lockfile (1) semble être un bon candidat, mais sachez que cela fait partie du paquet procmail , que vous n'avez peut-être pas encore installé sur votre ordinateur. C'est un paquet assez populaire pour qu'il soit packagé pour votre système s'il n'est pas encore installé. Trois des quatre systèmes que j'ai vérifiés l'ont et l'autre le dispose.
Son utilisation est simple:
Les options que je vous ai données permettent de réessayer une fois par seconde pendant 15 secondes maximum. Supprimez l'indicateur "-r" si vous souhaitez attendre indéfiniment.
la source
L'appel système
mkdir()
est atomique sur les systèmes de fichiers POSIX. Donc, en utilisant lamkdir
commande de telle sorte qu'elle implique exactement un appel, vousmkdir()
atteindriez votre but. (IOW, ne pas utilisermkdir -p
). Le déverrouillage correspondant estrmdir
bien sûr.Caveat emptor:
mkdir()
pourrait ne pas être atomique sur les systèmes de fichiers du réseau.la source
rmdir
donc aussi atomique?Peut-être que la commande lockfile fera ce dont vous avez besoin.
la source
Si vous utilisez uniquement Unix, utilisez fifos. Vous pouvez écrire des enregistrements de travail dans le fifo et faire en sorte que les processus soient lus à partir de ce fichier. Vos lecteurs bloquent alors sur le fifo.
Les fichiers de verrouillage sont ok, mais pour ce que vous décrivez, j'irais avec fifos
la source
Comme indiqué ici: " Corriger le verrouillage des scripts de shell? ", L’utilisation de l’ outil FLOM (Free LOck Manager) , la sérialisation des commandes et des scripts de shell sont aussi simples qu’exécuter
FLOM vous permet d'implémenter des cas d'utilisation plus souples (verrouillage distribué, lecteurs / rédacteurs, ressources numériques, etc.), comme expliqué ici: http://sourceforge.net/p/flom/wiki/FLOM%20by%20examples/
la source