web-dev-qa-db-fra.com

Commande Bash `wait`, en attente de l'exécution de plus d'un PID

J'ai récemment posté une question demandant s'il était possible de empêcher la réutilisation des PID } _.

Jusqu'à présent, la réponse semble être non. (Ce qui est bien.)

Cependant, l'utilisateur Diego Torres Milano a ajouté une réponse à cette question. Ma question concerne cette réponse.

Diego répondit:

Si vous avez peur de réutiliser les PID, ce qui ne se produira pas si vous attendez comme l'expliquent D'autres réponses, vous pouvez utiliser

echo 4194303 > /proc/sys/kernel/pid_max

pour diminuer votre peur ;-)

Je ne comprends pas vraiment pourquoi Diego a utilisé le chiffre 4194303 ici, mais c'est une autre question.

Je croyais comprendre que le code suivant me posait problème:

for pid in "${PIDS[@]}"
do
    wait $pid
done

Le problème étant que j'ai plusieurs PID dans un tableau et que la boucle for exécute la commande wait de manière séquentielle avec chaque PID du tableau, mais je ne peux pas prédire que les processus se termineront dans le même ordre que celui dans lequel leurs PID sont stockés. tableau.

c'est à dire; la suivante pourrait se produire:

  • Commencer à attendre le PID dans l'index de tableau 0
  • Le processus avec PID dans l'index 1 du tableau se termine
  • Le ou les nouveaux travaux sont exécutés sur le système, ce qui a pour résultat que le PID stocké dans l'index 1 du tableau PID est réutilisé pour un autre processus
  • wait se termine en tant que PID dans l'index de tableau 0
  • Commencez à attendre le PID dans l'index de tableau 0, sauf qu'il s'agit maintenant d'un processus différent et que nous n'avons aucune idée de ce que c'est
  • Le processus exécuté qui a réutilisé le PID que wait est en attente de never se termine. Peut-être est-ce le PID d'un serveur de messagerie ou quelque chose qu'un administrateur système a démarré.
  • wait continue d'attendre que le prochain bogue Linux grave soit détecté et que le système redémarre ou qu'il y ait une panne de courant

Diego a dit:

ce qui n'arrivera pas si vous attendez comme l'expliquent d'autres réponses

c'est à dire; que la situation que j'ai décrite ci-dessus ne peut pas se produire.

Diego a-t-il raison?

  • Si tel est le cas, pourquoi la situation décrite ci-dessus ne peut-elle pas se produire?

Ou est-ce que Diego n'est pas correct?

  • Si oui, alors je poste une nouvelle question plus tard dans la journée ...

Notes complémentaires

Il m'est arrivé de penser que cette question pourrait prêter à confusion, à moins que vous ne sachiez que les PID sont des PID de processus lancés en arrière-plan. c'est à dire;

my_function &
PID="$!"
PIDS+=($PID)
5
user3728501

Passons en revue vos options.

Attendre inconditionnellement tous les travaux en arrière-plan

for i in 1 2 3 4 5; do
    cmd &
done
wait

Cela a l'avantage d'être simple, mais vous ne pouvez pas garder votre ordinateur occupé. Si vous souhaitez commencer de nouveaux travaux alors que les anciens sont terminés, vous ne pouvez pas. Votre machine est de moins en moins utilisée jusqu'à ce que toutes les tâches en arrière-plan soient terminées. Vous pouvez alors démarrer un nouveau lot de tâches.

Lié est la capacité d'attendre un sous-ensemble de travaux en transmettant plusieurs arguments à wait:

unrelated_job &
for i in 1 2 3 4 5; do
  cmd & pids+=($!)
done
wait "${pids[@]}"   # Does not wait for unrelated_job, though

Attendez les travaux individuels dans un ordre arbitraire

for i in 1 2 3 4 5; do
   cmd & pids+=($!)
done

for pid in "${pids[@]}"; do
   wait "$pid"
   # do something when a job completes
done

Cela a l'avantage de vous permettre de travailler une fois le travail terminé, mais A toujours le problème suivant: les travaux autre que $pid peuvent se terminer en premier, laissant votre machine sous-utilisée jusqu'à ce que $pid soit terminé. Cependant, vous obtenez toujours le statut de sortie pour chaque travail, même s'il est terminé avant que vous ne l'attendiez.

Attendez que le suivant travail soit terminé (bash 4.3 ou plus tard)

for i in 1 2 3 4 5; do
   cmd & pids+=($!)
done

for pid in "${pids[@]}"; do
   wait -n
   # do something when a job completes
done

Ici, vous pouvez attendre que un travail soit terminé, ce qui signifie que vous pouvez garder votre machine aussi occupée que possible. Le seul problème est que vous ne savez pas nécessairement quel travail terminé, sans utiliser jobs pour obtenir la liste des processus actifs et la comparer à pids.

Autres options?

Shell n’est pas en soi une plate-forme idéale pour la distribution des tâches. C’est pourquoi il existe une multitude de programmes conçus pour gérer les tâches par lots: xargs, parallel, slurm, qsub, etc.

20
chepner

Ceci est ancien, mais le scénario présenté dans lequel une wait différée attend un processus aléatoire non lié en raison d'une collision entre pid n'a pas été directement pris en compte.

Ce n'est pas possible au niveau du noyau. Cela fonctionne de la manière suivante: avant que le processus parent appelle wait(2)¹, le processus enfant existe toujours . Parce que l'enfant existe toujours, Linux va manquer de pid plutôt que de le réutiliser. Cela se manifeste parfois avec des processus dits "zombies" ou "disparus" - ce sont des enfants qui sont sortis mais qui doivent encore être "récoltés" par leur parent.

Maintenant, au niveau du shell, vous n'avez pas à appeler wait(1)¹ pour que les processus enfants soient exploités - bash le fait automatiquement. Je ne l'ai pas confirmée, mais lorsque vous exécutez wait $pid pour un pid enfant qui est sorti il ​​y a longtemps, je parie que bash réalise qu'il a déjà récolté cet enfant et renvoie immédiatement les informations plutôt que d'attendre quoi que ce soit.

¹ la notation wait(N) est une convention utilisée pour lever la ambiguïté entre les couches de l'API - N désigne la section du manuel dans lequel se trouve une commande/fonction. Dans ce cas, nous avons:

  • wait(2): l'appel syscall - voir man 2 wait
  • wait(1): la commande shell - voir man 1 wait ou help wait

Si vous voulez savoir ce qui vit dans chaque section du manuel, essayez man N intro.

0
sqweek