OVH Cloud OVH Cloud

[Os.Fork()] Récupérer le Pid exact d'un processus enfant

11 réponses
Avatar
kilian
Bonjour à tous,

J'ai un petit problème avec les fork sous Python, c'est la première fois
que j'utilise les fork d'ailleurs....

Pour commencer j'utilise Python2.3 sous Debian Sarge.

Pour résumer, j'ai deux fichiers bash, l'un télécharge un flux mms:// ,
il s'appele dwl_raw
L'autre encode le fichier wave extrait, il s'appele raw_encode.

Voilà ce que donne mon fichier python:

-------------------------------------------------------------

#!/usr/bin/python2.3

import os,time

# Nom du fichier qui prend le stream brut
file_name=0

def launch_main(file_name):
os.system("./raw_encode "+str(file_name))

def launch_dwl(file_name):
os.system("./dwl_raw "+str(file_name))

# Daemon
while 1:
balance=os.fork()

# Balance vers le Processus fils
if balance==0:
launch_dwl(file_name)

# Balance vers le Processus père
time.sleep(30)

# Encodage

launch_main(file_name)
os.kill(balance,2)
os.remove("./dumps/"+str(file_name)+".wav")
file_name=file_name+1

---------------------------------------------------------------------------------------



Le fonctionnement général du programme ne pose aucun problème. En gros
il télécharge le flux pendant 30 secondes (avec mplayer). Puis
l'encodage se fait. Ensuite on kill le processus de téléchargement de
flux. On efface le fichier wave, et on recommence en incrémentant le nom
du fichier.

Ce qui me pose problème, c'est qu'on moment du kill(), la variable
balance contient un pid erronné.Donc le kill ne se fait pas (ou pas au
bon processus).

Exemple:
Je lance mon fichier Python.
Le téléchargement de mplayer se passe bien.
En tapant dans un shell bash:
ps aux | grep mplayer

J'ai deux processus mplayer:
16207 et 16208 (je ne sais pas pourquoi deux processus, mais bon ça a
l'air normal).

Je précise que j'ai rajouté :

print "\n\n Kill: "+str(balance)+"\n\n\n"

Juste au dessus du os.kill()

Donc au moment du kill j'ai ceci d'affiché:

kill: 16205

Donc ce n'est pas le même pid que celui (ou "ceux" finalement) de Mplayer.

Donc la boucle continue en rajoutant deux processus de Mplayer (ça fait
quatre). Et ça continue comme ça : j'en ai 6, 8 etc... Car le kill se
fait sur un pid erronné.

Mais je ne vois pas où est mon erreur. Ce n'est pas comme ça qu'on
récupère le pid d'un processus enfant?

Merci d'avance...

10 réponses

1 2
Avatar
tiissa
J'ai un petit problème avec les fork sous Python, c'est la première
fois

que j'utilise les fork d'ailleurs....


Tout le probleme vient de l'utilisation du fork.
fork retourne 0 pour le pere et le pid du pere pour le fils et non le
contraire.

Du coup dans votre script c'est le pere qui telecharge et que vous
essayez de tuer (remarquez le pid legerement inferieur).

Pour faire le contraire, j'utiliserais plutot un os.spawn*.

Avatar
Paul Gaborit
À (at) 19 May 2005 01:38:55 -0700,
écrivait (wrote):
J'ai un petit problème avec les fork sous Python, c'est la première
fois

que j'utilise les fork d'ailleurs....


Tout le probleme vient de l'utilisation du fork.
fork retourne 0 pour le pere et le pid du pere pour le fils et non le
contraire.


Et pourtant si.

os.fork retourne :
au père: le PID du fils (ou une valeur négative en cas d'erreur)
au fils: 0

Le problème vient en fait de l'utilisation de os.system qui crée un nouveau fils
à chacun des deux process. Pour conserver le meme PID, il vaut mieux utiliser
un appel à os.execl (ou l'une de ses nombreuses variantes) au moins pour le fils.

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>


Avatar
tiissa
Et pourtant si.


En effet. Pardon. Ca m'apprendra a ne pas relire le manuel pour
commenter des fonctions que je n'ai pas utilise depuis longtemps (et en
C en plus !).

à chacun des deux process. Pour conserver le meme PID, il vaut mieux
utiliser

un appel à os.execl (ou l'une de ses nombreuses variantes) au moins
pour le fils.




Dans son cas, ou le fils ne fait d'autre qu'un appel a un programme
externe, un spawn reste quand meme la solution la plus simple pour
remplacer a la fois le fork et le system/exec.

Avatar
Paul Gaborit
À (at) 19 May 2005 05:45:51 -0700,
écrivait (wrote):
à chacun des deux process. Pour conserver le meme PID, il vaut mieux
utiliser un appel à os.execl (ou l'une de ses nombreuses variantes) au
moins pour le fils.


Dans son cas, ou le fils ne fait d'autre qu'un appel a un programme
externe, un spawn reste quand meme la solution la plus simple pour
remplacer a la fois le fork et le system/exec.


On peut effectivement remplacer le couple os.fork/os.execl par un appel à
os.spawnl à condition d'utiliser le mode os.P_NOWAIT afin de récupérer l'ID du
process sous-jacent... puisqu'il faut pouvoir lui envoyer un signal à la fin.


--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>


Avatar
kilian
Paul Gaborit wrote:

On peut effectivement remplacer le couple os.fork/os.execl par un appel à
os.spawnl à condition d'utiliser le mode os.P_NOWAIT afin de récupérer l'ID du
process sous-jacent... puisqu'il faut pouvoir lui envoyer un signal à la fin.




Grand merci Paul et Tiissa pour vos réponses:-) Je comprends mieux
l'erreur alors.
Ca signifie que finalement quand je lance un nouveau process, c'est ma
fonction launch_dwl qui est le processus enfant. Et du coup, l'os.system
engendre encore un nouveau process, donc il a lui aussi son propre
Pid... C'est bien ça....?

Bon en tout cas je vais essayer tout de suite avec os.spawnl() et je
vous en donne des nouvelles bientôt...

Merci encore :-)

Avatar
kilian
Magnifique, ça marche :-)

Mais j'ai un soucis par contre.
En fait j'utilise os.spawnlp() avec la commande mplayer dedans et ses
arguments (car avec le fichier bash, je crois que le fichier bash avait
son propre processus, et mplayer aussi.....)

Et j'ai pris os.P_NOWAIT comme mode.

Le soucis n'est pas très grave mais j'aime bien faire les choses
propres... Quand je kill le processus fils, donc mplayer,(depuis le même
script python), et que je regarde après dans "ps aux", j'ai ceci:


kilian 17547 0.3 0.0 0 0 pts/17 Z+ 21:20 0:00 [mplayer]
<defunct>

Après quelques recherches, j'ai vu que ça signifiait que le programme a
bien été terminé mais qu'il subsiste en Zombie car "le processus parent
n'a pas lu sa valeur de retour", cf:
http://www.linux-france.org/lug/gulliver/ml-archives/avril-2004/msg00022.html

Et là....j'avoue que je ne sais pas trop quoi faire... :-/
Avatar
Paul Gaborit
À (at) Thu, 19 May 2005 21:33:33 +0200,
kilian écrivait (wrote):
Le soucis n'est pas très grave mais j'aime bien faire les choses
propres... Quand je kill le processus fils, donc mplayer,(depuis le même
script python), et que je regarde après dans "ps aux", j'ai ceci:


kilian 17547 0.3 0.0 0 0 pts/17 Z+ 21:20 0:00 [mplayer]
<defunct>

Après quelques recherches, j'ai vu que ça signifiait que le programme a bien
été terminé mais qu'il subsiste en Zombie car "le processus parent n'a pas lu
sa valeur de retour", cf:
http://www.linux-france.org/lug/gulliver/ml-archives/avril-2004/msg00022.html

Et là....j'avoue que je ne sais pas trop quoi faire... :-/


Le processus parent (du processus zombie de mplayer), c'est votre propre
script. Il vous suffit donc de faire appel à os.wait ou os.waitpid pour
récupérer cette valeur de retour et ne pas laisser un zombie de mplayer...

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>

Avatar
kilian

Le processus parent (du processus zombie de mplayer), c'est votre
propre

script. Il vous suffit donc de faire appel à os.wait ou os.waitpid
pour

récupérer cette valeur de retour et ne pas laisser un zombie de
mplayer...





D'accord. J'avais justement essayé os.waitpid() mais ça n'a aucun
effet:
soit les choses continuent comme avant (mplayer devient zombie) dans le
cas de l'option os.WNOHANG, soit il attend que le processus fils se
termine (avec os.WUNTRACED). Quant à l'option os.WCONTINUED il ne la
reconnait pas, pourtant j'ai bien python 2.3...

J'ai peut être oublié quelque chose....

Avatar
kilian
Ca y est j'ai trouvé. Pour tuer les processus zombie lorsqu'ils
apparaissent, il faut mettre os.waitpid(-1,os.WNOHANG) et voilà :-)

http://mail.python.org/pipermail/python-list/2001-December/077453.html

Je vois encore des zombies qui apparaissent parfois avec "ps aux" mais
ils disparaissent régulièrement...

Par contre je ne sais pas pourquoi "-1"...

Merci encore pour tout..
Avatar
tiissa
kilian wrote:
Ca y est j'ai trouvé. Pour tuer les processus zombie lorsqu'ils
apparaissent, il faut mettre os.waitpid(-1,os.WNOHANG) et voilà :-)
<snip>


Par contre je ne sais pas pourquoi "-1"...


D'après la doc [1], le -1 sert simplement à ne pas préciser quel fils on
attend.

[1]http://docs.python.org/lib/os-process.html

1 2