Comment déclencher et oublier un sous-processus?
Question
J'ai un long processus et j'en ai besoin pour lancer un autre processus (qui durera aussi longtemps). Je n'ai besoin que de le démarrer et de l'oublier complètement.
J'ai réussi à faire ce dont j'avais besoin en récupérant du code dans le livre Programming Ruby, mais j'aimerais trouver la meilleure façon, et comprendre ce qui se passe. Voici ce que j'ai au début:
exec("whatever --take-very-long") if fork.nil?
Process.detach($)
Alors, est-ce la bonne façon de faire ou comment devrais-je le faire?
Après avoir vérifié les réponses ci-dessous, je me suis retrouvé avec ce code, qui semble plus logique:
(pid = fork) ? Process.detach(pid) : exec("foo")
J'aimerais avoir des explications sur le fonctionnement de fork
. [Je l'ai déjà]
Le détachement de $$
était-il correct? Je ne sais pas pourquoi cela fonctionne et j'aimerais vraiment mieux comprendre la situation.
La solution
La fonction fork
sépare votre processus en deux.
Les deux processus reçoivent ensuite le résultat de la fonction. L’enfant reçoit la valeur zéro / nil
(et sait donc qu’il s’agit de l’enfant) et le parent reçoit le PID de l’enfant.
D'où:
exec("something") if fork.nil?
fera en sorte que le processus enfant commence par "quelque chose", et le processus parent continuera à son niveau actuel.
Notez que exec ()
remplace le processus actuel par "quelque chose" afin que le processus enfant n'exécute jamais aucun code Ruby ultérieur.
L'appel à Process.detach ()
semble indiquer qu'il est peut-être incorrect. Je me serais attendu à ce qu'il contienne le PID de l'enfant, mais si je lis correctement votre code, il détache le processus parent.
Autres conseils
Alnitak a raison. Voici un moyen plus explicite de l'écrire, sans $$
pid = Process.fork
if pid.nil? then
# In child
exec "whatever --take-very-long"
else
# In parent
Process.detach(pid)
end
L’objectif de détachement est juste de dire: "Je ne me soucie pas de la fin de l’enfant" éviter les processus zombie .
Détacher $$
n’était pas correct. À partir de p. 348 de la pioche (2e éd):
$$
Fixnum Numéro de processus du programme en cours d'exécution. [r / o]
Cette section, "Variables et constantes" dans la " Ruby Language " chapitre, est très pratique pour décoder diverses constantes $
ruby ??- quelle que soit l'édition en ligne (la première
Donc, ce que vous faisiez réellement était de détacher le programme de lui-même, pas de son enfant.
Comme d'autres l'ont déjà dit, le moyen approprié de se détacher de l'enfant consiste à utiliser le pid de l'enfant renvoyé par fork ()
.
Les autres réponses sont utiles si vous êtes certain de vouloir détacher le processus enfant. Toutefois, si cela ne vous dérange pas ou si vous préférez garder le processus enfant attaché (par exemple, vous lancez des sous-serveurs / services pour une application Web), vous pouvez tirer parti du raccourci suivant
fork do
exec('whatever --option-flag')
end
Fournir un bloc indique à fork d'exécuter ce bloc (et seulement ce bloc) dans le processus enfant, tout en continuant dans le parent.
J'ai trouvé les réponses ci-dessus cassées mon terminal et foiré la sortie. c'est la solution que j'ai trouvée.
system("nohup ./test.sh &")
juste au cas où quelqu'un aurait le même problème, mon objectif était de vous connecter à un serveur ssh, puis de faire en sorte que ce processus s'exécute indéfiniment. alors test.sh est-ce
#!/usr/bin/expect -f
spawn ssh host -l admin -i cloudkey
expect "pass"
send "superpass\r"
sleep 1000000