Un verrou de fichier est attaché à un fichier, via une description de fichier . À un niveau élevé, la séquence d'opérations dans une instance du script est la suivante:
- Ouvrez le fichier auquel le verrou est attaché («le fichier de verrouillage»).
- Prenez un verrou sur le fichier de verrouillage.
- Faire des trucs.
- Fermez le fichier de verrouillage. Cela libère le verrou attaché à la description de fichier créée en ouvrant un fichier.
Maintenir le verrou empêche l'exécution d'une autre copie du même script, car c'est ce que font les verrous. Tant qu'un verrou exclusif sur un fichier existe quelque part sur le système, il est impossible de créer une deuxième instance du même verrou, même via une description de fichier différente.
L'ouverture d'un fichier crée une description de fichier . Il s'agit d'un objet noyau qui n'a pas beaucoup de visibilité directe dans les interfaces de programmation. Vous accédez indirectement à une description de fichier via des descripteurs de fichier, mais vous le considérez normalement comme l'accès au fichier (lecture ou écriture de son contenu ou de ses métadonnées). Un verrou est l'un des attributs qui sont une propriété de la description du fichier plutôt qu'un fichier ou un descripteur.
Au début, lorsqu'un fichier est ouvert, la description du fichier a un seul descripteur de fichier, mais d'autres descripteurs peuvent être créés soit en créant un autre descripteur (la dup
famille d'appels système), soit en forçant un sous-processus (après quoi le parent et le l'enfant a accès à la même description de fichier). Un descripteur de fichier peut être fermé explicitement ou lorsque le processus dans lequel il se trouve meurt. Lorsque le dernier descripteur de fichier joint à un fichier est fermé, la description du fichier est fermée.
Voici comment la séquence d'opérations ci-dessus affecte la description du fichier.
- La redirection
<$0
ouvre le fichier de script dans le sous-shell, créant une description de fichier. À ce stade, un descripteur de fichier unique est attaché à la description: le numéro de descripteur 0 dans le sous-shell.
- Le sous-shell invoque
flock
et attend sa sortie. Pendant que flock est en cours d'exécution, deux descripteurs sont attachés à la description: le numéro 0 dans le sous-shell et le numéro 0 dans le processus de flock. Lorsque flock prend le verrou, cela définit une propriété de la description du fichier. Si une autre description de fichier a déjà un verrou sur le fichier, flock ne peut pas prendre le verrou, car il s'agit d'un verrou exclusif.
- Le sous-shell fait des trucs. Puisqu'il a toujours un descripteur de fichier ouvert sur la description avec le verrou, cette description continue d'exister et il conserve son verrou puisque personne ne supprime jamais le verrou.
- La sous-coquille meurt à la parenthèse fermante. Cela ferme le dernier descripteur de fichier sur la description de fichier qui a le verrou, donc le verrou disparaît à ce stade.
La raison pour laquelle le script utilise une redirection $0
est que la redirection est le seul moyen d'ouvrir un fichier dans le shell, et le maintien d'une redirection active est le seul moyen de garder un descripteur de fichier ouvert. Le sous-shell ne lit jamais à partir de son entrée standard, il suffit de le garder ouvert. Dans une langue qui donne un accès direct aux appels ouverts et fermés, vous pouvez utiliser
fd = open($0)
flock(fd, LOCK_EX)
do stuff
close(fd)
Vous pouvez réellement obtenir la même séquence d'opérations dans le shell si vous effectuez la redirection avec le programme exec
intégré.
exec <$0
flock -n -x 0
# do stuff
exec <&-
Le script peut utiliser un descripteur de fichier différent s'il souhaite continuer à accéder à l'entrée standard d'origine.
exec 3<$0
flock -n -x 0
# do stuff
exec 3<&-
ou avec un sous-shell:
(
flock -n -x 3
# do stuff
) 3<$0
Le verrou ne doit pas nécessairement se trouver sur le fichier de script. Il peut s'agir de n'importe quel fichier pouvant être ouvert en lecture (il doit donc exister, il doit s'agir d'un type de fichier pouvant être lu, tel qu'un fichier normal ou un canal nommé mais pas un répertoire, et le processus de script doit avoir l'autorisation de le lire). Le fichier de script a l'avantage qu'il est garanti d'être présent et lisible (sauf dans le cas de bord où il a été supprimé en externe entre le moment où le script a été appelé et le moment où le script arrive à la <$0
redirection).
Tant qu'il flock
réussit, et que le script se trouve sur un système de fichiers où les verrous ne sont pas bogués (certains systèmes de fichiers réseau tels que NFS peuvent être bogués), je ne vois pas comment l'utilisation d'un fichier de verrouillage différent pourrait permettre une condition de concurrence critique. Je soupçonne une erreur de manipulation de votre part.