Vous êtes sur la page 1sur 40

Communication interprocessus

Partie 2
Les entrées-sorties
Descripteurs
Descripteurs
Comment ça marche?
Flots par défaut
Les tubes anonymes
Les tubes anonymes
Les tubes anonymes
Les tubes anonymes
Communications unidirectionnels:
Les tubes anonymes
Les tubes anonymes
Les tubes anonymes
Les tubes anonymes
Le pipe est alors automatiquement partagé entre le père et le fils. Si l'un écrit dans le
pipe alors on ne sait pas lequel des deux va recevoir l'information. Ceci peut donner
des résultats inattendus.

Pour être certain de qui va écrire et qui va lire dans le pipe, il faut que les processus ferment
les extrémités qu'ils n'utilisent pas.

De cette façon le processus père peut être certain que s'il écrit dans le pipe ("fd[1]"), le fils va
recevoir l'information en lecture ("fd[0]").
Exemple 1
#include <stdio.h>
$ ./tube_exo1
#include <unistd.h>
$ bonjour bien reçu
int tube[2];
$
char buf[20];
main() {
pipe(tube);
if (fork()==0) { /* fils */
close(tube[0]);
write(tube[1], "bonjour", 8);
}
else { /* pere */
wait(NULL);
close(tube[1]);
read(tube[0], buf, 8);
printf("%s bien reçu\n", buf);
}
}
Exemple 2
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define R 0
#define W 1
int main()
{
int pid;
int fd[2];
char message[100];
int Nboctects;
char* phrase="VOICI MON MESSAGE POUR TOI PERE";
system("clear");
Exemple 2
printf("_____________________________________________\n");
printf("\t\tProcessus Courant:: %d\n",(int)getpid());
printf("_____________________________________________\n");
if (pipe(fd) == -1)
{
perror ("Creation du pipe a échoué ");
exit(1);
}
pid=fork();
if(!pid)
{
close(fd[R]);//fermeture du fichier de lecture par le fils
printf("\t\t\t\t\t\t+++++++++++++++++++++++++++++++++++++++\e[m\n");
printf("\t\t\t\t\t\t\t \e[29m Processus FILS:: %d\n",(int)getpid());
printf("\t\t\t\t\t\t+++++++++++++++++++++++++++++++++++++++\n");
printf("\t\t\t\t\t\t \e[29mProcessus FILS::PERE JE T'ENVOIE UN MESSAGE\n");
Exemple 2
if (write(fd[W],phrase,strlen(phrase)+1)== -1)
{
perror("write : Ecriture dans le pipe à échoué ");
exit(4);
}
close(fd[W]);//fermeture du fichier d'écriture par le fils
//sleep(2);
exit(3);
}
printf("%c[%d;%dm J'attends la terminaison du fils%c[%dm\n",27,1,33,27,0);
wait(NULL);
close(fd[W]);//fermeture du fichier d’écriture par le pere
Exemple 2

if (( Nboctects = read (fd[0],message, 100)) == -1)


{
perror ("read : Lecture échoué ");
exit(5);
}
message[Nboctects]='\0';
printf("%c[%d;%dmMESSAGE RECU :: nboctets = %d Message=
%s%c[%dm\n",27,1,33,Nboctects,message,27,0);
close(fd[R]);//fermeture du fichier de lecture par le pere
return 0;
}
Exemple 3
#include<sys/types.h>
#include<sys/wait.h> if(pipe(tube)==-1)
#include<unistd.h> {
#include<stdio.h> perror("Création pipe : ");
#include<string.h> exit(EXIT_FAILURE);
#include<stdlib.h> }
#include<assert.h> system("clear");
#define R 0 printf("_______________________________\n");
#define W 1 printf("\t\tProcessus Courant:: %d\n",(int)getpid());
int main(int argc,char* argv[]) printf("_______________________________\n");
{
int tube[2];
int pid;
char buf;
assert(argc==2);
Exemple 3
pid=fork();
if(pid==-1)
{
perror("Fork echec"); //PERE
exit(EXIT_FAILURE); close(tube[R]);
} write(tube[W],argv[1],strlen(argv[1])+1);
if(!pid)//FILS close(tube[W]);
{ printf("%c[%d;%dm J'attends la terminaison du
close(tube[W]); fils%c[%dm\n",27,1,33,27,0);
while(read(tube[R],&buf,1) > 0) wait(NULL);
{ printf("%c[%d;%dm BYE %c[%dm\n",27,1,33,27,0);
sleep(1); return 0;
write(STDOUT_FILENO,&buf,1); }
}
write(STDOUT_FILENO,"\n",1);
close(tube[R]);
exit(EXIT_SUCCESS);
}
Remarques

* Reprendre l’exemple 3 (inter blocage)


Les tubes anonymes :
Redirection de stdin et stdout
dup : duplique un descripteur et renvoie le premier descripteur libre dans la table du
processus
int fd = open("tutu",O WRONLY|O CREAT) ;
close(STDOUT_ FILENO) ;
dup(fd) ; // renvoie 1
close(fd) ; // ne sert plus à rien
printf("j'écris un truc") ; // écrit dans tutu
Descripteur Au début Après open Aprés close Après dup Après close
0 stdin stdin stdin stdin stdin
1 stdout stdout rien tutu tutu
2 stderr stderr stderr stderr stderr
3 rien tutu tutu tutu rien
stdin, stdout, stderr

Ces trois pipes sont par défault créés dans chaques processus. Le premier, stdin, est
branché par défaut sur l'entrée clavier tandis que stdout et stderr sont eux branchés sur
la sortie écran. Des descripteurs de fichiers par défaut leur sont associés : 0 pour stdin, 1
pour stdout, et 3 pour stderr.
Maintenant que l'on connait le principe de communication par pipe, on est tenté de
connecter ces pipes entre eux. Par exemple essayons de connecter stdout d'un premier
processus avec le stdin d'un second. Cette opération est effectuée par le shell à chaque
fois que deux commandes séparées par un pipe sont executées, par exemple pour relier
la sortie stdout de la commande ls avec l'entrée stdin de la commande wc, il faut taper
ceci dans un terminal : "ls | wc".
Pour réaliser ceci dans un programme en langage C, il faut procéder en plusieurs étapes.
Il faut commencer par créer un pipe vide : "fd=3" en écriture et "fd=4" en lecture.
On utilise donc la fonction "pipe(fd)" comme vue ci dessus.
Ensuite il faut que stdout du premier processus (fd1) soit connecté à l'entrée de notre pipe
(fd3) et que la sortie de notre pipe (fd4) soit connecté à stdin de notre second processus (fd0).
On appelera deux fois la fonction "dup2(param1, param2)" pour connecter fd1 à fd3 et fd4 à
fd0. "dup2" prend en argument deux paramètres, ce sont des descripteurs de fichiers : param1
vaudra fd3 et param2 vaudra fd1 car on veut que fd3 soit assimilé (ou connecté) à fd1. Pour le
second processus, param1 vaudra fd4 et parm2 vaudra fd0.
Finalement il faut fermer les extrémités de notre pipe pour éviter les comportements
étranges, c'est un peu le même problème que dans la section précedente. On utilisera
la commande "close(fd)" pour fermer les extremités de notre pipe.
Exemple 4
int execl (const char *app, const char *arg, ...);
app : chemin complet de l’application
arg : paramètre sous forme d’une liste d’argument,
termine par pointeur NULL

int main(int argc,char* argv[])


#include<sys/types.h>
{int pid;
#include<sys/wait.h>
int fd[2]; else
#include<unistd.h>
assert(argc==3); {
#include<stdio.h>
system("clear"); close(fd[R]);
#include<assert.h>
pipe(fd); dup2(fd[W],1);
#include<string.h>
pid=fork(); close(fd[W]);
#include<stdlib.h>
if(!pid) { if(execlp(argv[1],argv[1],NULL)==-1)
#define R 0
close(fd[W]); perror("execlp");
#define W 1
dup2(fd[R],0); }
close(fd[R]);
execlp(argv[2],argv[2],NULL);
}
return 0;
}
Execlp: la recherche de commande se fait dans la variable d’environnement PATH
Exercice

Écrire un programme C qui réalise la commande ls -al | wc -l en


créant deux processus qui communiquent à travers un tube.
Le fils écrit dans le tube en ayant au préalable redirigé sa sortie
standard à travers un tube ; quant au père il lit dans le tube en ayant
au préalable redirigé son entrée standard vers le tube.
Pour la redirection de la sortie et de l'entrée standard, utiliser la
fonction dup.
Utiliser la primitive de recouvrement execlp pour faire exécuter au
fils et au père les commandes ls et wc.
printf("pb exec ls -al");
exit(1);

Correction }
else
{
#include <stdio.h> perror("pb creation fils");
#include <stdlib.h> exit(1);
// le fils fait wc -l }
#include <sys/types.h> close(p[1]);
#include <sys/wait.h> close(STDIN_FILENO);
#include <fcntl.h> exit(0);
dup(p[0]); }
#include <unistd.h> close(p[0]);
int main(int argc, char **argv) execlp("/usr/bin/wc","wc","-l",(char *)NULL);
{ printf("pb exec wc -l");
int pid; exit(1);
int p[2]; }
if (pipe(p) < 0) else if (pid > 0)
{ {
perror("pb creation pipe"); // le père fait ls -al
exit(1); close(p[0]);
} close(STDOUT_FILENO);
pid = fork(); dup(p[1]);
if (pid == 0) close(p[1]);
{ execlp("/bin/ls","ls","-al",(char *)NULL);
Donner l’organisation d’une application de transmission
bidirectionnelle d’informations entre un processus père et un de
ses fils via des tubes : le père envoie 5 entiers au fils qui les affiche
et renvoie ces entiers multipliés par 2. Le père affiche ces doubles.
Écrire le programme C correspondant.
Dans ce problème, on crée deux tubes p1 et p2 pour faire
communiquer les deux processus :
– le père a accès en écriture sur p1 et en lecture sur p2,
– le fils a accès en écriture sur p2 et en lecture sur p1.
Exercice 2 : Tubes Anonymes(6 Points)
Considérez le programme suivant : On veut faire communiquer le processus père
#include <unistd.h> avec ses fils au moyen de deux tubes anonymes
#include <sys/types.h> (pipes sans nom) selon la figure suivante.
#include <sys/wait.h> La sortie standard du père est redirigée vers le
#define N 5 pipe1 qui devient l’entrée standard des fils. Les
void gestion(){ /* traitement */ }; sorties standards et erreurs des fils sont
/*0*/ redirigées vers le pipe2.
int main( ) Question : Complétez le code sous forme de
{ commentaires (/*0*/, /*1*/,….) de manière à
pid_t pid[N]; établir ces canaux de communication (supposez
int i; que le fork n’échoue jamais).
/*1*/
for ( i=0; i<N;i++)
if ((pid[i]=fork())==0)
{
/* 2*/
execlp("traitement", "traitement", NULL);
exit(1);
}
/*3*/
gestion( );
return 0;
}

Vous aimerez peut-être aussi