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:
wait
se termine en tant que PID dans l'index de tableau 0wait
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 courantDiego 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?
Ou est-ce que Diego n'est pas correct?
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)
Passons en revue vos options.
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
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.
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
.
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.
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
.