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 :

instructions dans un processus


Sujet :

C

  1. #1
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Décembre 2011
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Décembre 2011
    Messages : 14
    Points : 11
    Points
    11
    Par défaut instructions dans un processus
    Bonjour voila y'a quelque chose que je n'arrive pas a comprendre je débute dans la programmation système :

    voici mon code : il s'agit simplement de faire communiquer un processus père avec un processus fils

    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    void pipe_shell(char* argv1, char* argv2);
     
    int main(int argc,char* argv[])
    {
            if(argc!=3)
                     exit(-1);
     
    	pipe_shell(argv[1],argv[2]);
     
    	return EXIT_SUCCESS;
    }
     
    void pipe_shell(char* argv1, char* argv2)
    {
    	int tube[2];
    	pipe(tube);
    	pid_t result_fork=fork();
     
    	switch(result_fork)
    	{
    		case -1 : printf("Erreur creation processus\n");
    			exit(-1);
     
    		case 0 : /*processus fils*/
                            printf("coucou");
    			close(tube[1]);
    			dup2(tube[0],0);
    			close(tube[0]);
    			execl("/usr/bin/sort","sort",NULL);
    			break;
     
    		default : /*processus pere*/
    			printf("coucou");
    			close(tube[0]);
    			dup2(tube[1],1);
    			close(tube[1]);
    			execl("/bin/ls","ls",NULL);
     
    	}
    }
    Pourquoi les printf("coucou"); ne s'exécutent pas?

    De plus si j'ai bien compris les processus sont tués dès que leurs instructions sont terminés mais admettons que le fils doit envoyer un message au père via un pipe; Admettons que ce soit au père de s'exécuter en premier il va terminer ses instructions, voyant qu'il n'y a rien à lire pour le moment et ne pourra pas lire ce que le fils lui envoie puis va mourir? mais dans la réalité les deux arrivent à communiquer donc quand un processus meurt-il réellement?Tourne t-il en boucle plusieurs fois de suite?Ou lors de l'accès en lecture d'un descripteur va t-il se mettre en pause jusqu'a ce qu'une donnée apparaisse?

    Merci !

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Citation Envoyé par sin92 Voir le message
    Pourquoi les printf("coucou"); ne s'exécute pas?
    Ils s'executent au contraire mais la sortie standard est gérée avec un buffer.
    On ne vide le buffer pour écrire son contenu lorsque le buffer est plein, lorsqu'on rencontre le caractère '\n' ou lorsqu'on ferme le flux proprement.
    Ainsi le buffer est vidé après le dup2 qui redirige la sortie standard vers l'entrée du tube.


    Citation Envoyé par sin92 Voir le message
    De plus si j'ai bien compris les processus sont tués dès que leurs instructions sont terminés mais admettons que le fils doit envoyer un message au père via un pipe; Admettons que ce soit au père de s'exécuter en premier il va terminer ses instructions et ne pourra pas lire ce que le fils lui envoie mais dans la réalité les deux arrivent à communiquer donc quand un processus meurt-il réellement?
    execpl ne détruit pas le processus mais effectue un recouvrement.
    Ensuite, si le père se termine en premier, il me semble que le fils est adopté par init (à vérifier).

  3. #3
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Décembre 2011
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Décembre 2011
    Messages : 14
    Points : 11
    Points
    11
    Par défaut
    Le truc c'est que si je commente les exec, le printf affiche correctement coucou deux fois.
    De plus, printf se situe avant dup donc la sortie n'est pas encore reboucler dans mon tube, elle est encore liée à l'écran non?

    Oui si le père meurt le fils est adopté par init mais je me demande concernant la situation suivante : le fils envoie un message au père via un tube, il n'y a aucune boucle, donc toutes les instructions ne seront exécutées qu'une fois. si le père lit le tube avant que le fils n'écrive le message,il aura finit ses instructions et va mourir non? donc comment font-ils pour communiquer? puisque dans la pratique ils communiquent sans problème ?

  4. #4
    Membre expérimenté Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Points : 1 481
    Points
    1 481
    Par défaut
    Bonjour

    en dehors de l'aspect bufferisation pour le "coucou", tes problèmes viennent des lignes 32 et 40.

    Dans le fils, à la ligne 32, tu fermes tube[0] qui, depuis le dup2, est ... l'entrée standard. Donc pour lire (dans sort) ...

    Idem dans le père : à la ligne 40 tu fermes tube[1] qui est la sortie standard. Là, c'est le "ls" qui va écrire sur stdout ... qui est fermée.
    "La simplicité ne précède pas la complexité, elle la suit." - Alan J. Perlis
    DVP ? Pensez aux cours et tutos, ainsi qu'à la FAQ !

  5. #5
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Décembre 2011
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Décembre 2011
    Messages : 14
    Points : 11
    Points
    11
    Par défaut
    Alors justement ça aussi j'ai pas compris : mon programme simule simplement la commande ls | sort .

    Donc je redirige l'entrée de mon dup2 vers la sortie de mon processus ls (processus père) et je redirige la sortie de mon dup2 vers l'entrée de mon processus sort(processus fils) jusque la tout va bien.

    Mais les lignes 32 à 40,avec ou sans ces lignes, le programme marche niquel ça m'affiche bien ls | sort sur l'écran.

    Mais j'ai cru comprendre que ca faisait plus propre de fermer le dup2 sur les autres extrémités une fois la connection faite va savoir pourquoi...

  6. #6
    Membre expérimenté Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Points : 1 481
    Points
    1 481
    Par défaut
    Déjà, je suppose que les "coucou" n'étaient là que pour des problémes de débuggage. Si tu les oublies, avec les modifications/suppressions des lignes 32 et 40, le pipe programmé entre ls et sort fonctionne.

    Mais les lignes 32 à 40,avec ou sans ces lignes, le programme marche niquel ça m'affiche bien ls | sort sur l'écran.
    Ah ben non !!! Si tu les laisses, écrire sur stdout fermée et lire sur stdin fermée posent problème.

    Mais j'ai cru comprendre que ca faisait plus propre de fermer le dup2 sur les autres extrémités une fois la connection faite va savoir pourquoi...
    Une fois le "dup2(tube[0],0)" exécuté dans le fils, l'entrée standard (0) et tube[0] ne font plus qu'un seul et même "file descriptor". Si tu fermes tube[0] c'est strictement la même chose que de faire, dans le fils, close(0). Donc, soit la personne qui t'a dit que c'était + propre de faire cela n'y connait rien, soit tu as mal compris. Mais le résultat est celui que je décris.

    [EDIT] et problème analogue côté père, sur la sortie standard (1 <==> tube[1])
    "La simplicité ne précède pas la complexité, elle la suit." - Alan J. Perlis
    DVP ? Pensez aux cours et tutos, ainsi qu'à la FAQ !

  7. #7
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Décembre 2011
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Décembre 2011
    Messages : 14
    Points : 11
    Points
    11
    Par défaut
    Oui les coucou ne sont la que pour le débugage.

    Mais non je t'assure que ça ne pose aucun problème : la compilation marche niquel et le programme fonctionne correctement, même avec ces lignes.

    Regarde ce lien ou c'est expliquer :

    http://www.zeitoun.net/articles/comm...ar-tuyau/start

    Regarde la partie de simulation de ls|wc je te le copie ici :

    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
     
     if (pid == 0)
         {
           /* child */
           close(pfd[1]); /* close the unused write side */
           dup2(pfd[0], 0); /* connect the read side with stdin */
           close(pfd[0]); /* close the read side */
           /* execute the process (wc command) */
           execlp("wc", "wc", (char *) 0);
           printf("wc failed"); /* if execlp returns, it's an error */
           return 3;
         }
       else
         {
           /* parent */
           close(pfd[0]); /* close the unused read side */
           dup2(pfd[1], 1); /* connect the write side with stdout */
           close(pfd[1]); /* close the write side */
           /* execute the process (ls command) */
           execlp("ls", "ls", (char *)0);
           printf("ls failed"); /* if execlp returns, it's an error */
           return 4;
         }
       return 0;
      }
    Dans le code, il ferme TOUS les dup2 une fois la connection établie et de plus dans les cours du CNED il est bien dit qu'une fois la connection faite, toutes les sorties/entrées dup2 doivent être fermées.

    Et ca je comprend pas pourquoi on doit faire ça parce que comme tu le dis, ce n'est pas logique de fermer une entrée et une sortie d'un dup si on s'en sert pourtant sur le site que je t'ai linker et dans les cours du cned c'est comme cela qu'il font.

  8. #8
    Membre expérimenté Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Points : 1 481
    Points
    1 481
    Par défaut
    Ooops ... J'ai effectivement dit des âneries (et insisté ...). Désolé.

    Une fois le "dup2(tube[0],0)" exécuté dans le fils, l'entrée standard (0) et tube[0] ne font plus qu'un seul et même "file descriptor". Si tu fermes tube[0] c'est strictement la même chose que de faire, dans le fils, close(0).
    Non en fait le close invalide le file descriptor (l'entier) mais le fichier référencé est toujours accessible via l'autre (ou les autres) file descriptor "clones/dupliqués". J'avais oublié que (man 2 close):

    DESCRIPTION
    close() closes a file descriptor, so that it no longer refers to any file
    and may be reused
    . Any record locks (see fcntl(2)) held on the file it was
    associated with, and owned by the process, are removed (regardless of the
    file descriptor that was used to obtain the lock).

    If fd is the last file descriptor referring to the underlying open file
    description (see open(2)), the resources associated with the open file
    description are freed; if the descriptor was the last reference to a file
    which has been removed using unlink(2) the file is deleted.

    Citation Envoyé par sin92
    Dans le code, il ferme TOUS les dup2 une fois la connection établie et de plus dans les cours du CNED il est bien dit qu'une fois la connection faite, toutes les sorties/entrées dup2 doivent être fermées.

    Et ca je comprend pas pourquoi on doit faire ça parce que comme tu le dis, ce n'est pas logique de fermer une entrée et une sortie d'un dup si on s'en sert pourtant sur le site que je t'ai linker et dans les cours du cned c'est comme cela qu'il font.

    Le nombre de fichiers simultanément ouverts par un process a une valeur max. Donc, si un fichier ne sert pas/plus, on le ferme.

    Une fois les branchements effectués (1 sur tube[1] côté père, 0 sur tube[0] côté fils), on a 2 file descriptors qui référencent le même fichier, et dans le fils, et dans le père. Comme le but est de faire à la suite des exec de ls et sort, il ne faut surtout pas fermer 0 et 1 mais tube[0] et tube[1] car sort va lire sur 0/stdin (et pas 3) et ls va écrire sur 1/stdout (et pas 4).


    Un bout de code qui montre tout ça (rien d'extraordinaire, c'est juste pour poser les choses) :

    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <errno.h>
    #include <assert.h>
     
     
    int main(int argc,char *argv[])
    {
        int  max_open = 3;   // 0 (stdin), 1 (stdout) et 2 (stderr) deja ouverts
        int  i;
        char chaine[128];
     
        // je duplique la sortie standard autant de fois que possible
        // (valeur dépendant de l'OS mais qui peut parfois (toujours ?) etre modifiee)
        while (dup2(1,max_open) == max_open)
            max_open++; 
     
        fprintf(stderr,"%s\n",strerror(errno)); 
        fprintf(stderr,"max %d fichiers ouverts simultanement\n",max_open);
     
     
        // ecriture sur tous les nouveaux fichiers ouverts/crees via dup2
        // (pour montrer que ca part bien sur la sortie standard)
        for (i=3;i<max_open;i++)
        {
            write(1,"stdout: ",8);
            sprintf(chaine,"chaine ecrite sur fd %d\n",i);
            write(i,chaine,strlen(chaine));
        }
     
        // fermeture de tous les fichiers dup2liques avec verif
        for (i=3;i<max_open;i++)
            assert(close(i) == 0);
     
        // re-tentative d'ecriture sur fd 3
        strcpy(chaine,"ne devrait jamais s'afficher");
        if (write(3,chaine,strlen(chaine)) == -1)
            fprintf(stderr,"l'ecriture a normalement echoue : %s\n",strerror(errno));
     
        // des ecritures "classiques" sur stdout / 1 fonctionnent toujours
        strcpy(chaine,"ecriture chaine sur fd 1\n");
        write(1,chaine,strlen(chaine));
        fprintf(stdout,"ca marche aussi avec stdout\n");
    }
    à l'exécution (sous Linux/Ubuntu) :

    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
    plx@sony:~/Bureau/DVP/pipe$ ./pipe
    Bad file descriptor
    max 1024 fichiers ouverts simultanement
    stdout: chaine ecrite sur fd 3
    stdout: chaine ecrite sur fd 4
    stdout: chaine ecrite sur fd 5
    stdout: chaine ecrite sur fd 6
    stdout: chaine ecrite sur fd 7
    stdout: chaine ecrite sur fd 8
    stdout: chaine ecrite sur fd 9
    stdout: chaine ecrite sur fd 10
    stdout: chaine ecrite sur fd 11
    stdout: chaine ecrite sur fd 12
    ...
    stdout: chaine ecrite sur fd 1018
    stdout: chaine ecrite sur fd 1019
    stdout: chaine ecrite sur fd 1020
    stdout: chaine ecrite sur fd 1021
    stdout: chaine ecrite sur fd 1022
    stdout: chaine ecrite sur fd 1023
    l'ecriture a normalement echoue : Bad file descriptor
    ecriture chaine sur fd 1
    ca marche aussi avec stdout
    plx@sony:~/Bureau/DVP/pipe$

    Enfin, pour revenir à tes fameux "coucou", Neckara t'a tout dit sur la bufferisation et les conditions de vidage de ce buffer : buffer plein, passage à la ligne ou fermeture du fichier. Alors pourquoi n'apparait-il pas ?

    Cette bufferisation se fait dans le contexte des structures FILE. C'est bien ça que tu utilises quand tu fais un printf (donc fprintf(stdout,...).

    The fclose() function flushes the stream pointed to by fp (writing any
    buffered output data using fflush(3)
    ) and closes the underlying file
    descriptor.

    Quand la sortie standard du père est fermée (lors du dup2 de la ligne 39), dup2 (appel système) n'appelle pas fclose de la bibliothèque C "générale". Donc vider un buffer ? quel buffer ?


    Avec fclose, vidage du buffer :

    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
    plx@sony:~/Bureau/DVP/pipe$ more fclose.c
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc,char* argv[])
    {
        printf("coucou");
        fprintf(stderr,"avant le fclose(stdout)\n");
        fclose(stdout);
    }
    plx@sony:~/Bureau/DVP/pipe$ make fclose
    cc     fclose.c   -o fclose
    plx@sony:~/Bureau/DVP/pipe$ ./fclose
    avant le fclose(stdout)
    coucouplx@sony:~/Bureau/DVP/pipe$
    mais avec close, rien du tout :

    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
    plx@sony:~/Bureau/DVP/pipe$ more close.c
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(int argc,char* argv[])
    {
        printf("coucou");
        fprintf(stderr,"avant le close(1)\n");
        close(1);
    }
    plx@sony:~/Bureau/DVP/pipe$ make close
    cc     close.c   -o close
    plx@sony:~/Bureau/DVP/pipe$ ./close
    avant le close(1)
    plx@sony:~/Bureau/DVP/pipe$
    "La simplicité ne précède pas la complexité, elle la suit." - Alan J. Perlis
    DVP ? Pensez aux cours et tutos, ainsi qu'à la FAQ !

Discussions similaires

  1. [XUP] 2up ou XP ou bien les deux dans le processus de développement
    Par nabilblk dans le forum Méthodes Agiles
    Réponses: 4
    Dernier message: 01/11/2007, 19h58
  2. Détection automatique d'1 appli dans les processus
    Par FredericB dans le forum C++Builder
    Réponses: 2
    Dernier message: 31/01/2006, 23h38
  3. plusieurs instructions dans un onClick
    Par illegalsene dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 25/01/2006, 11h10
  4. instructions dans url
    Par le69 dans le forum Langage
    Réponses: 5
    Dernier message: 15/11/2005, 07h07
  5. Instruction dans le IF
    Par Juny dans le forum PostgreSQL
    Réponses: 5
    Dernier message: 13/02/2005, 17h05

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