Can $! provoquer des conditions de concurrence lorsqu'il est utilisé dans des scripts fonctionnant en parallèle?

8

Disons que j'ai plusieurs scripts bash qui s'exécutent en parallèle, avec du code comme celui-ci:

#!/bin/bash

tail -f /dev/null &
echo "pid is "$!

Est-il $!garanti de me donner le PID de la tâche d'arrière-plan la plus récente de ce script , ou s'agit-il de la tâche d'arrière-plan la plus récente au niveau mondial? Je suis simplement curieux de savoir si le fait de compter sur cette fonctionnalité peut provoquer des conditions de concurrence lorsque le PID qu'il renvoie provient d'un processus démarré dans un autre script.

philraj
la source

Réponses:

16

$!est garanti pour vous donner le pid du processus dans lequel le shell a exécuté cette tailcommande. Les shells sont à thread unique, chaque shell vit dans son propre processus avec son propre ensemble de variables. Il n'y a aucun moyen que le $!shell va fuir dans un autre shell, tout comme l'attribution d'une variable shell dans un shell n'affectera pas la variable du même nom dans un autre shell (si nous mettons de côté les variables universelles du fishshell) .

Maintenant, tail -f /dev/nullc'est une commande qui s'exécute indéfiniment, mais pour les commandes de courte durée, notez que comme il y a un nombre limité d'ID de processus possibles, les ID de processus finissent inévitablement par être réutilisés.

Dans:

true &
pid=$!

Cela $pidcontiendra l'identifiant du processus où le shell s'est exécuté true, mais au moment où vous l'utilisez $pid, ce pid pourrait bien être mort et pourrait faire référence à un processus différent.

Stéphane Chazelas
la source
3
Oui, j'étais au courant de votre deuxième point, et que si vous voulez créer un gestionnaire de processus d'arrière-plan fiable, vous devez utiliser un langage qui garantit que vous saurez le moment exact où un processus enfant s'est terminé et son PID a été retourné au pool. , ce qui, apparemment, ne peut pas shell car ils récoltent agressivement les processus enfants. Merci pour l'explication claire.
philraj
5
@philraj, dans zsh, vous pouvez installer des gestionnaires sur SIGCHLD qui sont traités à la fin des travaux asynchrones et utilisés $jobstate/$jobtextpour inspecter l'état du processus. Pas sans race car l'enfant est déjà récolté au moment où le piège est exécuté, mais cela signifie des fenêtres de course très courtes où les pids sont très peu susceptibles d'être déjà réutilisés.
Stéphane Chazelas