Sve@r | Sve@r a écrit :
Déjà, essaye juste avec 3 programmes en dur style "ls |sort |more".
Génère 3 fils et 2 tubes
Si ça marche, il te sera facile d'étendre à tous les programmes passés en paramètre.
|
Ce petit TP m'a plu et je me suis amusé à le faire.
Voici le source n° 1 (les programmes sont lancés dans l'ordre demandé)
Code :
- #include <sys/types.h> // Types prédéfinis "c"
- #include <sys/wait.h> // Attente fin de process
- #include <unistd.h> // Standards Unix
- #include <stdio.h> // I/O fichiers classiques
- #include <fcntl.h> // Contrôle fichiers bas niveau
- #include <stdlib.h> // Standard librairies
- // Structure qui gère les processus à lancer
- typedef struct {
- char *arg[100]; // Nom programme plus arguments
- int pid; // N° processus
- int status; // Code retour
- }t_pgm;
- // Structure qui gère les pipes
- typedef struct {
- int cote[2]; // Cotés du tube
- }t_pipe;
- typedef enum {lire=0, ecrire} e_cote;
- void fermeture(int, t_pipe*, int); // Fermeture tubes inutilisés
- int main(int argc, char *argv[])
- {
- int pid; // Pid fils
- int i; // Indice de boucle
- int nb_process; // Nb processus à lancer
- t_pipe *tabTube; // Tableau des tubes
- static t_pgm tabPgm[]={
- {{"cat", "/etc/passwd", NULL}, 0, 0},
- {{"sort", "-r", NULL}, 0, 0},
- {{"sed", "s/:/;/g", NULL}, 0, 0},
- {{"sed", "s/home/maison/g", NULL}, 0, 0},
- {{"tr", "'[a-z]'", "'[A-Z]'", NULL}, 0, 0},
- {{NULL}, 0, 0},
- }; // Tableau des programmes à lancer
- t_pgm *ptPgm; // Ptr balayage tabPgm
- // Récupérer le nb de processus
- for (ptPgm=tabPgm, nb_process=0; ptPgm->arg[0] != NULL; ptPgm++, nb_process++);
- // Création du tableau de tubes (un tube de moins que le nb de processus)
- if ((tabTube=(t_pipe*)malloc((nb_process - 1) * sizeof(t_pipe))) == NULL)
- {
- perror("malloc" );
- exit(-1);
- }
- // Création des tubes
- for (i=0; i < (nb_process - 1); i++)
- {
- fprintf(stderr, "Création tube %d\n", i);
- if (pipe(tabTube[i].cote) != 0)
- {
- perror("pipe" );
- free(tabTube);
- exit(-2);
- }
- }
- // Lancement de chacun des processus
- for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
- {
- switch(pid=fork())
- {
- case 0: // Fils
- fprintf(stderr, "fils (%d) - pid=%d\n", i, getpid());
- // Fermeture tubes inutilisés par ce processus
- fermeture(i, tabTube, nb_process - 1);
- // Pour tous les fils autres que le premier
- if (i > 0)
- {
- // Redirection entrée venant du tube précédent
- close(STDIN_FILENO);
- dup2(tabTube[i - 1].cote[lire], STDIN_FILENO);
- }
- // Pour tous les fils autres que le dernier
- if (i < (nb_process - 1))
- {
- // Redirection sortie sur mon tube
- close(STDOUT_FILENO);
- dup2(tabTube[i].cote[ecrire], STDOUT_FILENO);
- }
- // Lancement du processus
- execvp(ptPgm->arg[0], ptPgm->arg);
- exit(0);
- default: // Père
- tabPgm[i].pid=pid;
- //sleep(1);
- }
- }
- // Fermeture des tubes non utilisés par le père
- fermeture(-1, tabTube, nb_process - 1);
- // Attente de la fin de tous les processus
- for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
- waitpid(ptPgm->pid, &ptPgm->status, 0);
- // Affichage de l'exécution
- for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
- {
- if (WIFSIGNALED(ptPgm->status))
- fprintf(stderr, "Pgm <%s> - Terminé par kill(%d)\n", ptPgm->arg[0], WTERMSIG(ptPgm->status));
- else
- fprintf(stderr, "Pgm <%s> - Terminé par exit(%d)\n", ptPgm->arg[0], WEXITSTATUS(ptPgm->status));
- }
- // Libération mémoire
- free(tabTube);
- return(0);
- }
- // Fonction qui ferme les tubes inutilisés
- void fermeture(int fils, t_pipe *tabTube, int nb_tube)
- {
- int i; // Indice de boucle
- fprintf(stderr, "fermeture tubes processus(%d)\n", fils);
- for (i=0; i < nb_tube; i++)
- {
- // Si on n'est pas sur le tube de notre prédécesseur
- if (i != (fils - 1))
- {
- close(tabTube[i].cote[lire]);
- fprintf(stderr, "\tfermeture(%d) %d.lire\n", fils, i);
- }
- // Si on n'est pas sur notre propre tube
- if (i != fils)
- {
- close(tabTube[i].cote[ecrire]);
- fprintf(stderr, "\tfermeture(%d) %d.ecrire\n", fils, i);
- }
- }
- }
|
Voici le source n° 2 (les programmes sont lancés dans l'ordre inverse)
Code :
- #include <sys/types.h> // Types prédéfinis "c"
- #include <sys/wait.h> // Attente fin de process
- #include <unistd.h> // Standards Unix
- #include <stdio.h> // I/O fichiers classiques
- #include <fcntl.h> // Contrôle fichiers bas niveau
- #include <stdlib.h> // Standard librairies
- // Structure qui gère les processus à lancer
- typedef struct {
- char *arg[100]; // Nom programme plus arguments
- int pid; // N° processus
- int status; // Code retour
- }t_pgm;
- // Structure qui gère les pipes
- typedef struct {
- int cote[2]; // Cotés du tube
- }t_pipe;
- typedef enum {lire=0, ecrire} e_cote;
- void fermeture(int, t_pipe*, int); // Fermeture tubes inutilisés
- int main(int argc, char *argv[])
- {
- int pid; // Pid fils
- int i; // Indice de boucle
- int nb_process; // Nb processus à lancer
- t_pipe *tabTube; // Tableau des tubes
- static t_pgm tabPgm[]={
- {{"tr", "'[a-z]'", "'[A-Z]'", NULL}, 0, 0},
- {{"sed", "s/home/maison/g", NULL}, 0, 0},
- {{"sed", "s/:/;/g", NULL}, 0, 0},
- {{"sort", "-r", NULL}, 0, 0},
- {{"cat", "/etc/passwd", NULL}, 0, 0},
- {{NULL}, 0, 0},
- }; // Tableau des programmes à lancer
- t_pgm *ptPgm; // Ptr balayage tabPgm
- // Récupérer le nb de processus
- for (ptPgm=tabPgm, nb_process=0; ptPgm->arg[0] != NULL; ptPgm++, nb_process++);
- // Création du tableau de tubes (un tube de moins que le nb de processus)
- if ((tabTube=(t_pipe*)malloc((nb_process - 1) * sizeof(t_pipe))) == NULL)
- {
- perror("malloc" );
- exit(-1);
- }
- // Création des tubes
- for (i=0; i < (nb_process - 1); i++)
- {
- fprintf(stderr, "Création tube %d\n", i);
- if (pipe(tabTube[i].cote) != 0)
- {
- perror("pipe" );
- free(tabTube);
- exit(-2);
- }
- }
- // Lancement de chacun des processus
- for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
- {
- switch(pid=fork())
- {
- case 0: // Fils
- fprintf(stderr, "fils (%d) - pid=%d\n", i, getpid());
- // Fermeture tubes inutilisés par ce processus
- fermeture(i, tabTube, nb_process - 1);
- // Pour tous les fils autres que le premier
- if (i > 0)
- {
- // Redirection sortie sur le tube précédent
- close(STDOUT_FILENO);
- dup2(tabTube[i - 1].cote[ecrire], STDOUT_FILENO);
- }
- // Pour tous les fils autres que le dernier
- if (i < (nb_process - 1))
- {
- // Redirection entrée venant de mon tube
- close(STDIN_FILENO);
- dup2(tabTube[i].cote[lire], STDIN_FILENO);
- }
- // Lancement du processus
- execvp(ptPgm->arg[0], ptPgm->arg);
- exit(0);
- default: // Père
- tabPgm[i].pid=pid;
- //sleep(1);
- }
- }
- // Fermeture des tubes non utilisés par le père
- fermeture(-1, tabTube, nb_process - 1);
- // Attente de la fin de tous les processus
- for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
- waitpid(ptPgm->pid, &ptPgm->status, 0);
- // Affichage de l'exécution
- for (i=0, ptPgm=tabPgm; i < nb_process; i++, ptPgm++)
- {
- if (WIFSIGNALED(ptPgm->status))
- fprintf(stderr, "Pgm <%s> - Terminé par kill(%d)\n", ptPgm->arg[0], WTERMSIG(ptPgm->status));
- else
- fprintf(stderr, "Pgm <%s> - Terminé par exit(%d)\n", ptPgm->arg[0], WEXITSTATUS(ptPgm->status));
- }
- // Libération mémoire
- free(tabTube);
- return(0);
- }
- // Fonction qui ferme les tubes inutilisés
- void fermeture(int fils, t_pipe *tabTube, int nb_tube)
- {
- int i; // Indice de boucle
- fprintf(stderr, "fermeture tubes processus(%d)\n", fils);
- for (i=0; i < nb_tube; i++)
- {
- // Si on n'est pas sur le tube de notre prédécesseur
- if (i != (fils - 1))
- {
- close(tabTube[i].cote[ecrire]);
- fprintf(stderr, "\tfermeture(%d) %d.ecrire\n", fils, i);
- }
- // Si on n'est pas sur notre propre tube
- if (i != fils)
- {
- close(tabTube[i].cote[lire]);
- fprintf(stderr, "\tfermeture(%d) %d.lire\n", fils, i);
- }
- }
- }
|
Les informations qu'affichent chacun de ces deux programmes sont affichées sur le canal "STDERR". On peut donc les shunter en redirigeant ce canal "2" vers "/dev/null".
En fait, qu'on lance les processus à l'endroit ou à l'envers, ça marche. Message édité par Sve@r le 05-04-2005 à 15:17:06
|