IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

fork() et pipe(), eof non lu


Sujet :

C

  1. #1
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut fork() et pipe(), eof non lu
    Salut à tous,

    J'ai un petit problème concernant une application que je suis en train de développer. Je précise que je suis tout frais dans le mode du C.

    Le principe est assez simple, le voici :

    Je fais un appel à pipe() pour créer un tube, puis j'utilise fork() après avoir correctement redirigé les entrées et sorties standards pour que le fils puisse lancer l'application ctags. ctags lira les fichier à traiter dans son entrée standard pendant que le père enverra les fichiers sur sa (celle du père), sortie standard. Voici le principe en bouts de code (Je précise que j'ai tout écrit à la main donc si il y'a des erreurs de syntaxe il s'agit simplement de faute de frappe. Tout A L'AIR de bien fonctionner, ctags crée et remplie bien le fichier de tags)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    int * tube;
     
    if(pipe(tube)){
      [...]
    }
     
    switch(fork()){
       [...]
        case 0:
             close(tube[1]);
             dup2(tube[0], STDIN_FILENO);
              [ ...
                    <lance "ctags -L -" avec execvp() pour lire l entrée standard>
               ... ];
     
       default:
             close(tube[0]);
             dup2(tube[1], STDOUT_FILENO);
             [ ...
                  <lance la fonction qui ecrit les fichier à traiter dans la sortie standard!>
             ... ]
    }
     
    [ <le reste traite normalement avec stdin et stdout> ]
    Tout marche bien, le ctags me sort bien un fichier de tags Seulement voilà la fonction en question dans le père est sensée écrire un EOF dans le tube (sa sortie standard). Ce que je fais avec un fwrite(stdout, "%d", stdout) car j'ai lu que fputc() convertit de façon transparente un entier, quel qu'il soit, en caractère (Je débute encore en C et ces notions sont encore un peu vague pour moi donc dans le doute...!). Puis la "fonction père" ferme sa sortie standard (ce que je fais avec un close() ).

    Mon problème est que lorsque j'envoie le EOF dans stdout et même quand je ferme mon stdout dans le père, le ctags reste quand même bloqué et attend encore d'autres noms de fichiers.

    Alors voici ma question, y'a-t-il un moyen genre un attribut du pipe, portable si possible, que je pourrais changer pour que le EOF soit transmis directement au fils? Bien sûr j'ai posé ma question en étant sûr que çà vient de là mais je débute vraiment en C alors si je me gourre n'hésitez pas à me lyncher! A ce propos d'ailleurs je précise que j'ai fais un test en envoyant, juste pour tester, un nombre de EOF correspondant à la taille d'un buffer pour les pipe mais là ctags m'affiche je ne sais combien de fois un caractère bizarre avant de me dire que le nom de fichier est trop long.

    Donc j'en profite pour poser une deuxième question histoire d'être sûr :
    Mon caractère EOF (-1 sur mon système linux), est-il bien passé tel quel à la sortie standard?? Et de façon plus générale quelle serait la meilleure fonction pour écrire des données "brutes" dans ce genre de situation sans formattage par fprintf et autres??

  2. #2
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    On n'écrit pas "EOF" comme tu essaies de le faire. EOF n'est pas une valeur qu'on transmet, c'est juste une manière pour fread() d'indiquer qu'on a atteint la fin des données. Si fread() renvoit EOF c'est parce que la fin du fichier a été atteinte, pas parce qu'un caractère "EOF" a été lu dans le fichier. En pratique dans le cas d'un pipe on a EOF quand il n'y a plus de données à lire dans le pipe, et que l'autre bout a été fermé.

    Donc dans le père il faut simplement faire un fclose() du fichier dans lequel tu écrit les données (en passant, tu n'as pas besoin de faire un dup2, tu peux très bien écrire les données dans tube[0]).

    Tu sembles mélanger des fonctions sur les fd (close) et des fonctions sur les streams (fwrite). Il ne faut pas.

    Si tu veux plus d'aide il faudrait le code du père qui envoie les données au fils.

  3. #3
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Salut et merci de ta réponse,

    En fait le dup2 c'est pour pouvoir travailler avec la sortie standard dans le père et l'entrée standard dans le fils vu que ctag va lire dedans.



    La fonction du père ne fais rien d'autre qu'écrire dans sa sortie standard des chaines de caractères. je te donne un exemple plus court :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    int main(void){
       int * tube;
       char * commande[]= {"ctags", "-L", "-", (char *) NULL};
     
       pipe(tube);
     
       switch(fork()){
          case 0:
                 close(tube[1]);
                 dup2(tube[0], STDIN_FILENO);
                  if(execvp("ctags", commande)){
                      strerror(errno);
                      exit(1);
                  break;
     
           default:
                 close(tube[0]);
                 dup2(tube[1], STDOUT_FILENO);
                  sleep(5); /* le temps que ctags se lance */
                  fprintf(stdout, "test.c\n");
                  fflush(stdout);
                  fclose(stdout);
                  return(0);
       }
    }
    j'ai volontairement omis le traitement des erreurs.

    Maintenant je ne controle pas ctags donc je ne peux pas faire un fclose sur stdin dans le fils. Et le problème c'est que ctags reste en attente sur stdin. Je voudrais juste simuler l'appui d'un ^d (eof) en mode interractif quand la fonction du père a fini. seulement le fd reste ouvert dans ctags et je n'y peut rien. le fd ne se ferme que lorsque je tape une touche dans le shell. Donc je suppose que pour fermer ctags, il faut lui envoyer explicitement le eof, mais comment? Comment simuler le ctrl-d dans le fd?

    merci encore

  4. #4
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Rebonjour,

    bon alors il n'y a vraiment personne qui aurait un semblant de réponse???

  5. #5
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2010
    Messages
    254
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2010
    Messages : 254
    Par défaut
    Au lieu d'uiliser un sleep pour temporiser, utilise plutot une fonction de la famille wait. Ces fonctions vont attendre que le fils termine sont execution avant de continuer l'execution du père.

  6. #6
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Merci de ta réponse mais je n'utilise pas ces fonctions car comme tu as pu le voir dans mon code le père ne se contente pas d'attendre la fin du fils et heureusement car le fils lui attend les "instruction" du père via son entrée standard. Une fonction de la famille wait waitpid etc... bloquerait mon programme indéfiniment.

    Mais là on s'écarte du sujet. Pour mon problème de EOF? Personne n'a vraiment jamais envoyé de EOF sur autre chose qu'un terminal?

  7. #7
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Je l'ai déjà expliqué, EOF ne "s'envoie" pas. Il faut fermer le fd comme tu le fais. D'ailleurs le code que tu donnes fonctionnes (sauf que tu as inversé tube[0] et tube[1], mais je suppose que c'est une erreur de recopie puisque c'était bon dans tes messages précédents).

    A mon avis le problème est ailleurs. Difficile à dire sans voir ton code exact.

    Le sleep() est inutile. Le père peut tout à fait écrire dans le pipe, et même le fermer, avant le exec() du fils. Ca ne pose aucun problème.

  8. #8
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Bon en fait la réponse était toute simple et j'ai même un peu honte! (il a fallut un petit tour sur gdb après m'être demandé pourquoi les fprintf étaient affichés à l'écran. En gros le temps que çà monte au cerveau! Ah les joies de la programmation ) Le problème venait de ma déclaration du tube.
    Sans faire un malloc et sans vérifier le retour de l'appel pipe (qui me renvoie un Bad address).

    ou un résout le problème.
    Je suis surpris que ce code fonctionne chez toi Matafan tu dois avoir un bon compilo ou la chance du vétéran Et désolé de ne pas avoir poster le code original mais c'est juste que c'était un mix de flex et de C "normal" en 2 voir 3 modules donc c'était plus simple de poster un exemple mais il n'y avait pas de manip du fichier lui même à part des fprintf.()

    Sinon je sais bien pour le buffer et du fd et qu'en général on écrit pas de EOF sur un fichier quand on veut l'envoyer à la lecture mais vu que le code ne marchait pas (surtout pour le buffer) et la note dans le man de ctags j'ai cru que... Enfin bon Ce qu'il faut aussi se dire aussi c'est que le EOF qui est envoyé lorsqu'on ferme le fd n'est qu'un "arrangement" que les fread() et autres de la libc offrent pour éviter au programmeur de coder la vérification si on a atteint la fin du fichier/buffer ou pas!

    Enfin bref je passe le topic en résolu mais une dernière question : celà devrait être possible non? A quoi sert, ou plutot quand utilise-t-on la macro EOF définie dans la libc (libio inclut dans stdio je crois)? Si par exemple un jour je veux indiquer une fin de fichier sans pour autant fermer le fd (disons pour une réutilisation ultérieure), est-ce possible ou dois-je absolument fermer et réouvrir un autre descripteur, qui est quand même plus lourd si çà doit se faire régulièrement. Imaginons que je veuille lancer un ctags par fichier écrit et que je passe par une autre fonction qui revient à l'appelant, je dois vraiment faire des fclose(), fopen() et dup2() à chaque fois?

    Vraiment désolé de vous avoir fait perdre votre temps de la sorte . Un gros merci à vous deux quand même pour vos réponses. :

  9. #9
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    En fait je n'ai pas copié collé ton code, j'ai écrit mon propre code semblable au tient. J'ai pas fait gaffe à la déclaration du pipe.

    La macro EOF sert à tester le retour des fonctions du style fread(), et à rien d'autre. Pour un fichier normal on peut évidemment arriver à la fin du fichier, voir un EOF, puis recommencer à lire le fichier sans le fermer et le réouvrir. Mais pour des pipes ça n'a pas de sens, car les pipes ne sont pas "seekable". Une fois qu'on a lu une donnée dans un pipe, la donnée n'est plus dans le pipe.

    Pour ton histoire de ctags je ne suis pas sûr de comprendre, mais tu ferais exactement comme tu le fais ici : tu écris les fichiers successivement sur le même pipe sans le fermer, séparés par des "\n".

  10. #10
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2009
    Messages
    172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2009
    Messages : 172
    Par défaut
    Je comprends bien maintenant ce que tu veux dire. La macro EOF est en fait une valeur que les fread() et consor renvoient en cas d'échec (la fin de fichier est en soit un échec) et non la valeur lue mais si elle est utilisé pour çà je trouve un peu brouillon d'avoir nommé cette macro de la sorte ou même fait une macro pour çà surtout qu'on doit vérifier que la fin du fichier est effectivement atteinte avec feof() et ferror()! C'est source de confusion. J'aurais trouvé plus clair de dire que ces fonctions renvoient -1 ou une valeur négative directement puisque que lire un nombre d'octet négatif est impossible! Bref c'est bizarre

    Sinon quant à l'utilité d'écrire un EOF dans un pipe, c'est dans l'exemple que je donne :

    Imagine que je veuille le même programme, mais avec un fichier de tag différent par fichier traité, ce qui implique que je lance un processus ctag par fichier traité, avec des milliers de fichiers à traiter. Je lance mes ctags avec des popen() pour revenir dans la fonction appelante mais le problème c'est que je dois fermer le fichier à la fin de chaque ctag lancé. Il faut donc que je crée un autre fd, si je travaille avec la sortie standard dans les autres parties du programme que je fasse un dup2(), sinon que j'ouvre un flux sur le fd. 3 appels système par fichier pour un millier de fichier çà fait beaucoups alors qu'il me suffirait que d'un

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    for i=0; i < nbFichiers; i++{
          fprintf(stdout, "%s\n", tab_NomFichiers[i]);
          /* Envoie de fin de fichier */
          /*ctag se ferme */
          execvp("ctags", param);
    }
    1 appel système (execvp) par fichier si il était possible d'envoyer un EOF dans un flux qui mettrait fin à chaque application ctag lancées.

    A moins que d'autres solutions existent? Mais pour l'instant je vois déjà çà comme utilité de pouvoir envoyer un EOF dans 1 fichier sans le fermer.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. EOF non détecté sur appel sqlplus
    Par theophanie77460 dans le forum SGBD
    Réponses: 1
    Dernier message: 23/03/2012, 17h21
  2. Fork et pipe
    Par Ylias dans le forum Shell et commandes GNU
    Réponses: 6
    Dernier message: 30/05/2006, 09h13
  3. Caractère EOF non reconnu
    Par rod59 dans le forum C
    Réponses: 14
    Dernier message: 11/11/2005, 17h15
  4. [PERL] Problème en essayant de comprendre fork et pipe
    Par LE NEINDRE dans le forum Langage
    Réponses: 6
    Dernier message: 04/10/2005, 15h23
  5. Réponses: 3
    Dernier message: 16/03/2004, 16h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo