ISTIC 2018-2019
Communication entre processus par tubes anonymes
Amira BELHEDI [email protected]
Référence livre Programmation système en C sous Linux Signaux, processus, threads, IPC et sockets
Communication par les tubes (pipes)
- Tube de communication: canal ou tuyau (en anglais pipe) dans lequel un processus peut écrire des données (producteur, écrivain ou rédacteur) et un autre processus peut les lire (consommateur).
- C’est un moyen de communication unidirectionnel inter- processus. C’est le moyen de communication le plus simple entre deux processus.
- Pour avoir une communication bidirectionelle entre deux processus, il faut créer deux tubes et les employer dans des sens opposés.
- Il existe 2 types de tubes:
- Un tube possède deux extrémités – une est utilisée pour la lecture – l’autre pour l’écriture.
- La gestion des tubes se fait en mode FIFO
- La lecture dans un tube est destructrice.
- Un tube a une capacité finie.
- Le tube est créé par appel de la primitive « pipe() », déclaré dans « unistd.h ».
- La création d'un tube correspond à celle de deux descripteurs de fichiers,
- En cas de succès, le tableau «p» est remplit par les descripteurs des 2 extrémités du tube qui seront utilisés pour accéder (en lecture/écriture) au tube.
- Par définition:
Publicité
– Le descripteur d'indice 0 (p[0]) désigne la sortie du tube, il est ouvert en lecture seule. – Le descripteur d'indice 1 (p[1]) désigne l'entrée du tube, il est ouvert en écriture seule.
6/33
Tubes anonymes
- La valeur retournée par « pipe() »:
- Fermeture d'un descripteur
- Une fois le tube est créé, il est directement utilisable. (pas besoin de l’ouvrir)
- On doit fermer les descripteurs dont on n’a plus besoin avec la primitive «close()». close (int fd)
- Exemple:
- L’écriture dans un tube se fait avec la primitive «write()» en utilisant le descripteur p[1]. int write (int p[1], void *zone, int nb_car); – « p[1] » : descripteur du flux. – « zone » : pointeur sur la zone mémoire contenant les données à écrire dans le tube. – « nb_car »: nombre d'octets (caractères) que l’on souhaite écrire dans le tube.
- Code retour:
- Si le tube est plein → l’appelant est bloqué
- Un tube peut avoir plusieurs producteurs (possibilité d’entrelacement)
- Un producteur dans le tube est un processus qui détient le descripteur associé à ce tube. – Le signal « SIGPIPE » arrête l’exécution du processus.
- Lorsqu’un processus tente d’écrire dans un tube sans lecteur → il reçoit le signal SIGPIPE et il sera interrompu (si on ne traite pas ce signal). main () { int p[2]; pipe (p); // création de tube close (p [0]); // descripteur en lecture est fermé printf(“ Debut d’ecritue dans le tube ”); if ( write(p[1],"abc",3)==-1)
- Résultat d’exécution: Ce programme affiche le message « Debut d’ecritue dans le tube » et s'arrête.
Publicité
12/33
Lecture dans un tube
- La lecture s’effectue avec la primitive de lecture de fichier « read()»
- Code retour:
- Remarques:
- Si le tube contient moins de « nb_car » octets, l’appelant est bloqué: – jusqu’à ce qu’il y ait au moins « nb_car » octets dans le tube. – ou jusqu’à ce que ce tube ne soit plus ouvert en écriture (close(p[1])).
- Si un lecteur tente de lire dans un tube vide alors:
- Utilisation de l'appel système fork()
- Supposons que le père écrit dans le tube et le fils lit dans le tube
- Le processus crée le tube ; 2. Le processus fait un appel à fork() pour créer un fils. →Le père et le fils possèdent chacun un descripteur en lecture et en écriture sur le même tube 3. Le père ferme son descripteur en lecture. Le fils ferme son descripteur en écriture sur le tube. 4. Le processus père peut écrire sur le tube ; les valeurs écrites pourront être lues par le fils.
- Exercice
- Le père doit envoyer une chaine de caractère à son fils, puis attendre sa terminaison
- Le fils doit lire et afficher cette chaine.
Publicité
20/33
#include <stdio.h> #include <unistd.h> #define TAILLE 30 main () {char envoi , reception ;
int p [2], i, pid,val, etat; strcpy ( envoi, "texte transmis au tube"); val=pipe(p) ; if (val==-1) {
printf ("erreur de creation du tube "); exit (1); }else { pid = fork();
if (pid == -1) {
printf("erreur de creation du fils"); exit (2); }
if (pid > 0) /* le père écrit dans le tube */
{
close(p[0]) ; write (p[1], envoi, TAILLE); close (p[1]) ; wait (&etat); }
if (pid == 0) /* le fils lit à partir du tube */
{close(p[1]);
read (p[0], reception, TAILLE); printf (" --> %s\n", reception); close (p[0]); exit (0); } } }
Duplication de descripteurs
- Duplication de descripteurs avec les primitives:
- Les primitives "dup" and "dup2"
- le nouveau descripteur dans le cas de succès
- -1 dans le cas d’échec
- Après un appel réussi à "dup" ou "dup2",
- utile pour la redirection des flots d’entrées-sorties
- particulièrement utiles lors du recouvrement de processus
- Exercice
- dup ou dup2 et• execlp variante de la primitive exec (expliqué dans ce qui suit)
Publicité
26/33
Primitive exec()
- La famille de primitives « exec() »
- Diverses variantes de la primitive « exec() » existent et diffèrent selon le type et le nombre de paramètres passés.
- La primitive «execlp() »
- Exemple: pour exécuter la commande « ls », « fiche » vaut "ls". – « arg0 »: est le nom du programme à exécuter. En général identique au premier si aucun chemin explicite n’a été donné. Par exemple si le premier paramètre est "ls", « arg0 » vaut aussi: "ls".
- Exemple