Création et synchronisation de processus. Communications par signaux, par tubes.



Documents pareils
Cours Programmation Système

Programmation système en C/C++

Introduction aux Systèmes et aux Réseaux

Cours 6 : Tubes anonymes et nommés

LEs processus coopèrent souvent pour traiter un même problème. Ces

TRAVAUX PRATIQUES Programmation Système Langage C / Système UNIX. 2 e année Génie Informatique

Les processus 2/54. Qu est-ce qu un processus? 3(6)/54. Se souvenir 1(1)/54. Le système de fichiers (exemple du disque dur)

Les processus. Système L3, /39

Qu'est-ce qu'un processus: Définitions

Programmation système

3IS - Système d'exploitation linux - Programmation système

Programmation système de commandes en C

Les processus légers : threads. Système L3, /31

03/04/2007. Tâche 1 Tâche 2 Tâche 3. Système Unix. Time sharing

DUT Informatique Module Système S4 C Département Informatique 2009 / Travaux Pratiques n o 5 : Sockets Stream

École Polytechnique de Montréal. Département de Génie Informatique et Génie Logiciel. Cours INF2610. Contrôle périodique.

Processus! programme. DIMA, Systèmes Centralisés (Ph. Mauran) " Processus = suite d'actions = suite d'états obtenus = trace

ENSP Strasbourg (Edition ) Les Systèmes Temps Réels - Ch. DOIGNON. Chapitre 3. Mise en œuvre : signaux, gestion du temps et multi-activités

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

Le système GNU/Linux IUP NTIC /11/05

Système et réseaux (SR1) Gestion des utilisateurs

Communication Interprocessus

Exécutif temps réel Pierre-Yves Duval (cppm)

Le prototype de la fonction main()

Programmation Système (en C sous linux) Rémy Malgouyres LIMOS UMR 6158, IUT département info Université Clermont 1, B.P.

Cours de S.E. les Signaux

Introduction à la Programmation Parallèle: MPI

Chapitre 4 : Outils de communication centralisés entre processus

Algorithmique et Programmation, IMA

Le traitement du temps

Programmation système I Les entrées/sorties

1/24. I passer d un problème exprimé en français à la réalisation d un. I expressions arithmétiques. I structures de contrôle (tests, boucles)

Unix : Programmation Système

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

Gestion des processus


IN Cours 1. 1 Informatique, calculateurs. 2 Un premier programme en C

Introduction au langage C

Outils pour la pratique

Cours de Systèmes d Exploitation

Plan global. Programmation système II. Socket du domaine UNIX. Plan. Socket UNIX, Terminaux, Async IO, Mémoire, ELF.

Le Langage C Version 1.2 c 2002 Florence HENRY Observatoire de Paris Université de Versailles florence.henry@obspm.fr

Exceptions. 1 Entrées/sorties. Objectif. Manipuler les exceptions ;

Java Licence Professionnelle CISII,

Programmer en JAVA. par Tama

Le système de gestion des fichiers, les entrées/sorties.

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

TP : Gestion d une image au format PGM

MISE A NIVEAU INFORMATIQUE LANGAGE C - EXEMPLES DE PROGRAMMES. Université Paris Dauphine IUP Génie Mathématique et Informatique 2 ème année

Problèmes liés à la concurrence

Playing with ptrace() for fun and profit

Formation Technicien Supérieur de Support en Informatique T2SI. Le module LINUX. Session J04 Version 01

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java

REALISATION d'un. ORDONNANCEUR à ECHEANCES

Cours Informatique Master STEP

Le langage C. Séance n 4

Archivage Messagerie Evolution pour usage HTML en utilisant Hypermail

Cours intensif Java. 1er cours: de C à Java. Enrica DUCHI LIAFA, Paris 7. Septembre Enrica.Duchi@liafa.jussieu.fr

Cours de Système : Gestion de Fichiers

I. Introduction aux fonctions : les fonctions standards

Architecture d un système d exploitation

Applications client/serveur TCP/IP - Sockets Rappels. C.Crochepeyre Applications CS 1

Dans le chapitre 1, nous associions aux fichiers ouverts des descripteurs de fichiers par lesquels nous accédions aux fichiers.

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère

Simulation d un système de paiement par carte bancaire

Plan du cours. Historique du langage Nouveautés de Java 7

Cours 14 Les fichiers

1. Structure d'un programme FORTRAN 95

Développement d un logiciel de messagerie instantanée avec Dotnet (version simplifiée)

Communication par sockets

INTRODUCTION AUX SYSTEMES D EXPLOITATION. TD2 Exclusion mutuelle / Sémaphores

Introduction à la programmation concurrente

Les structures. Chapitre 3

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Chapitre 2. Les processus. 2.1 Introduction. 2.2 les différents états d un processus

SYSTÈME DE GESTION DE FICHIERS

STS SE. FreeRTOS. Programmation réseau WIFI. Programmation réseau. Socket Tcp. FlyPort smart Wi-Fi module

Initiation. àl algorithmique et à la programmation. en C

SYSTÈME DE GESTION DE FICHIERS SGF - DISQUE

Programmation C++ (débutant)/instructions for, while et do...while

Les structures de données. Rajae El Ouazzani

Temps Réel. Jérôme Pouiller Septembre 2011

Structure d un programme

Systèmes d exploitation Gestion de processus

Algorithmique & Langage C IUT GEII S1. Notes de cours (première partie) cours_algo_lgc1.17.odp. Licence

Cours Langage C/C++ Programmation modulaire

Lier Erlang avec d autres langages de programmation

Licence Bio Informatique Année Premiers pas. Exercice 1 Hello World parce qu il faut bien commencer par quelque chose...

Introduction à la programmation Travaux pratiques: séance d introduction INFO0201-1

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

Initiation à la programmation en Python

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars

TD3: tableaux avancées, première classe et chaînes

Un ordonnanceur stupide

GESTION DES FICHIERS C/UNIX

Notions fondamentales du langage C# Version 1.0

Chap III : Les tableaux

Exclusion Mutuelle. Arnaud Labourel Courriel : arnaud.labourel@lif.univ-mrs.fr. Université de Provence. 9 février 2011

INTRODUCTION À LA PROGRAMMATION CONCURRENTE

Cours 1 : Introduction. Langages objets. but du module. contrôle des connaissances. Pourquoi Java? présentation du module. Présentation de Java

Transcription:

Création et synchronisation de processus. Communications par signaux, par tubes. Un processus est un ensemble d'octets (en langage machine) en cours d'exécution, en d'autres termes, c'est l'exécution d'un programme. Les processus sous Unix apportent : - La multiplicité des exécutions. Plusieurs processus peuvent être l'exécution d'un même programme. - Le protection des exécutions. Un processus ne peut exécuter que ses instructions propres et ce de façon séquentielle ; il ne peut pas exécuter des instructions appartenant à un autre processus. Les processus sous Unix communiquent entre eux et avec le reste du monde grâce aux appels système. La création d'un processus - fork() Sous Unix, la création d'un processus est réalisée par l'appel système fork(). Cet appel système permet de créer dynamiquement (en cours d exécution) un nouveau processus qui s exécute de façon concurrente avec le processus qui l a créé. Le nouveau processus exécute le même code que le processus parent et démarre comme lui au retour du fork(). Le seul moyen de distinguer le processus fils du processus père est que la valeur de retour de la fonction fork est 0 dans le processus fils créé et est égale au numéro du processus fils nouvellement créé, dans le processus père et -1 en cas d échec. # include <unistd.h> pid_t fork(void); L utilisation classique de la fonction fork est la suivante : # include <unistd.h> # include <stdio.h> int pid; pid = fork ( ) ; if (pid == - 1) /* code si échec : printf ( le fork ( ) a échoué \n ) */ Mastère M2 IISA S1 1/12

if (pid == 0) /* code correspondant à l'exécution du processus fils */ else /* code correspondant à l'exécution du processus père */ Exercice Ecrire un programme "C" qui crée deux processus (un père et son fils). Chacun d'eux affichera à l'écran qui il est ("je suis le père de PID :??", je suis le fils de PID :?? et de père de PID :??). Afin de connaître le PID (=numéro d'identification d'un processus) du processus en cours, la fonction int getpid() s'impose. Pour le processus père, c'est la commande int getppid(). Rappel : pour compiler sous Unix, la commande à réaliser dans le terminal est : cc -o proc.exe proc.c. Où proc.c est le fichier où le code est écrit et proc.exe l'exécutable. La fonction fork ( ) dans une boucle Pour mieux comprendre le fonctionnement de la fonction de création de processus ( fork ( ) ), nous allons l'utiliser dans une boucle itérative. Ecrire un programme en C qui fait appel à la fonction fork ( ) dans une boucle for (i=0; i<3; i++). A l'intérieur de chaque itération le programme affichera les informations suivantes : (i : valeur_de_i) je suis le processus : pid, mon pere est : ppid, retour : retour où valeur_de_i est la valeur du compteur de la boucle pid est le PID du processus courant, ppid est le PID du processus père du processus courant, retour est la valeur du code retour de l'appel à la fonction fork ( ). La fonction - execl ( ) La fonction execl() illustre le mécanisme complémentaire à celui de la création de processus implanté via la fonction fork(), dont dispose UNIX. Le principe que nous allons voir ici revient à modifier le code du programme à exécuter pendant l'exécution du code en cours. Ecrire un programme appelé bonjour dont le code affiche à l'écran la chaîne suivante : bonjour. Ecrire et lancer le programme suivant qui fait appel au programme bonjour via la méthode execl ( ) : #include <unistd.h> int main ( ) printf ( preambule du bonjour\n ); execl (./bonjour,(char *) 0); printf ( postambule du bonjour\n ); Qu'en conclure? La synchronisation entre processus : fork(), wait(), waitpid(), system(). Mastère M2 IISA S1 2/12

Les processus créés par des fork() s exécutent de façon concurrente avec leur père. Ne pouvant présumer de la politique et de l état de l ordonnanceur du système, il sera impossible de déterminer quels processus se termineront avant tels autres (y compris leur père). Dans certains cas le père meurt avant la terminaison de son fils ; à la terminaison du fils, on dira que ce dernier est dans un état zombi (dans l affichage de la commande "ps", S=Z). Le noyau rattache ces processus au processus init (1). D où l existence, dans certains cas, d un problème de synchronisation. Primitives de synchronisation : wait(), waitpid() La primitive wait permet l élimination des processus zombis et la synchronisation d un processus sur la terminaison de ses descendants avec récupération des informations relatives à cette terminaison. Elle provoque la suspension du processus appelant jusqu à ce que l un de ses processus fils se termine. #include <sys/types.h> #include <sys/wait.h> pid_t wait (int *pointeur_status) Introduite dans la norme POSIX, la primitive waitpid permet de sélectionner parmi les fils du processus appelant un processus particulier. Exercice Les deux programmes ci-dessous proposent une première approche de synchronisation entre deux processus père et fils. Dans le second, il y a deux fils. Le père est synchronisé de telle sorte qu'il se termine après la terminaison du deuxième fils. Ecrire ces deux programmes. Les exécuter et en analyser le fonctionnement. // premier programme #include <unistd.h> main() int pid; int status; switch(pid=fork()) case -1: perror("création de processus\n"); exit(2); case 0: printf("je suis le fils\n"); printf("valeur de fork = %d\n", pid); printf("je suis le processus %d de père %d\n", getpid(),getppid()); printf("fin du fils\n"); exit(0); default : wait(&status); printf("je suis le père\n"); printf("valeur de fork = %d\n", pid); printf("je suis le processus %d de père %d\n", getpid(),getppid()); printf("fin du père\n"); exit(128); // deuxième programme Mastère M2 IISA S1 3/12

#include <unistd.h> main() int pid_fils1, pid_fils2, pid_courant; int status; pid_fils1=fork(); pid_courant=getpid(); switch(pid_fils1) case -1: perror("pb dans la création du 1er fils\n"); exit(2); case 0: printf("%d: je suis le 1er fils du processus %d\n", pid_courant,getppid()); printf("%d: fin du processus\n",pid_courant); exit(0); default : switch(pid_fils2=fork()) case -1: perror("pb dans la création du 2ème fils\n"); exit(3); case 0: printf("%d: Je suis le 2nd fils du processus %d\n",getpid(),getppid()); sleep(2); printf("%d: fin du processus\n",getpid()); exit(1); default : printf("%d: je suis le père et j'attends mon fils de pid %d\n",pid_courant,pid_fils2); waitpid(pid_fils2,&status,0); printf("%d: fin du père\n",pid_courant); exit(128); Exercice Regarder dans le manuel la commande system( ). Ecrire un programme qui débute par l'affichage de BONJOUR, se poursuit par l'exécution de la commande "ls -l" et se termine par l'affichage de BONSOIR. Si "man system" ne fonctionne pas : system - appeler une commande shell int system(commande) char *commande ; Le fonction system appelle le shell, et lui passe la commande commande comme si elle avait été tapée au terminal. L'exécution est suspendue jusqu'à ce que la commande soit finie. Si system ne peut lancer la commande, une valeur négative est renvoyée. Mastère M2 IISA S1 4/12

La synchronisation entre processus et le traitement des signaux sous Unix. Un signal est "un message très court" qu un processus peut envoyer à un autre processus, pour lui dire qu un événement particulier est arrivé (Intuitivement, ils sont comparables à des sonneries, les différentes sonneries indiquant des événements particuliers). Le processus pourra alors mettre en œuvre une réponse décidée et pré-définie à l avance (handler). Ce mécanisme est implanté par un moniteur, qui scrute en permanence l occurrence des signaux. C est par ce mécanisme que le système communique avec les processus utilisateurs en cas d erreur (violation mémoire, erreur d E/S) ou à la demande de l utilisateur lui-même (caractères d interruption ^D,^C...). En fait il n existe qu une vingtaine de signaux numérotés à partir de 1. Ces signaux portent également des noms (cf. liste des principaux signaux ci-dessous). On les trouve dans "/usr/include/signal.h". Envoyer un signal revient à envoyer ce numéro à un processus. Tout processus à la possibilité d émettre à destination d un autre processus un signal à condition que ses numéros de propriétaires (UID) lui en donnent le droit vis-à-vis de ceux du processus récepteur. Les principaux signaux : SIGHUP (1) il est envoyé lorsque la connexion physique de la ligne est interrompue ou en cas de terminaison du processus leader de la session ; SIGINT (2) frappe du caractère intr (interruption clavier) sur le clavier du terminal de contrôle ; SIGQUIT (3) frappe du caractère quit (interruption clavier avec sauvegarde de l image mémoire dans le fichier de nom core) sur le clavier du terminal de contrôle ; SIGKILL (9) signal de terminaison non déroutable. SIGTERM (15) signal de terminaison, il est envoyé à tous les processus actifs par le programme shutdown, qui permet d arrêter proprement un système UNIX. Terminaison normale. SIGILL (4) Instruction illégale. SIGFPE (8) Erreur arithmétique. SIGUSR1 (10) Signal 1 défini par l utilisateur. SIGSEGV (11) Adressage mémoire invalide. SIGUSR2 (12) Signal 2 défini par l utilisateur. SIGPIPE (13) Écriture sur un tube sans lecteur. SIGALRM (14) Alarme. SIGCHLD (17) Terminaison d un fils. SIGCONT (18) Reprise du processus. SIGSTOP (19) Suspension du processus (non déroutable). SIGTSTP (20) Émission vers le terminal du caractère de suspension. SIGTTIN (21) Lecture du terminal pour un processus d arrière-plan. SIGTTOU (22) Écriture vers le terminal pour un processus d arrière-plan. Lorsqu un processus reçoit un signal, il exécute une routine spéciale. Cette routine peut être une routine standard du système ou bien une routine spécifique fournie par l utilisateur. Il est également possible d ignorer la réception d un signal, c est-à-dire de n exécuter aucun traitement. L Envoi de signaux Pour envoyer un signal à un processus, on utilise la commande appelée kill. Celle-ci prend en option (c est-à- dire précédée du caractère - ) le numéro du signal à envoyer et en argument le numéro du (ou des) processus destinataire(s). $ kill -TERM pid_process Mastère M2 IISA S1 5/12

La commande kill utilisée avec l argument -l renvoie la liste des signaux du système : $ kill -l HUP INT QUIT ILL TRAP IOT EMT FPE KILL BUS... TTOU $ En langage C, une fonction permet aussi de réaliser ceci : int kill (pid_t pid, int sig); Un tel appel à cette primitive a pour effet d envoyer le signal de numéro sig au(x) processus déduit(s) de la valeur de pid. Les processus destinataires sont les suivants en fonction de la valeur de pid : <-1 tous les processus du groupe pid -1 tous les processus du système (sauf 0 et 1) 0 tous les processus dans le même groupe que le processus > 0 processus d identité pid. Voici un exemple d utilisation de handler définis par l utilisateur : #include <signal.h> /* handler utilisateur "bonjour" et "bonsoir" */ void bonjour (int sig) printf ("bonjour à tous\n"); void bonsoir (int sig) printf ("bonsoir à tous\n"); signal (SIGUSR2, bonsoir); int i; main () /* "armement" des signaux */ signal (SIGUSR1, bonjour); signal (SIGUSR2, bonsoir); for (;;); Sur l exemple précédent, on pourra envoyer dans le shell, les signaux correspondants aux processus à l aide de la commande kill : $ kill -USR1 pid $ kill -USR2 pid Exercice Ecrire le programme précédent, et l'exécuter. Mastère M2 IISA S1 6/12

Au retour du handler appelé lors de la délivrance d un signal capté, l exécution du processus reprend, sauf demande contraire, au point où le processus a été interrompu. Il existe d autres primitives permettant la synchronisation des processus. C est le cas des primitives sleep et pause. - La primitive sleep (int durée) permet de bloquer (état endormi) le processus courant sur la durée passée en paramètre. - La primitive pause permet de mettre le processus courant en attente de l arrivée de signaux. #include <unistd.h> int pause (void); Exercice Ecrire un programme dans lequel un processus crée un fils et initialise un handler (afficher BONJOUR) sur SIGUSR1. Le fils affiche des informations à l'écran puis envoie le signal SIGUSR1 à son père. Attention le programme fils doit se terminer avant le processus père. La sortie (les messages sur l'écran) du programme devra ressembler à ceci : père : Je suis le processus 27406 fils : Je suis le processus 27407 père : j'attends un signal BONJOUR fils : fin du processus père : fin du processus La communication par tubes. Les tubes sont un mécanisme de communication qui permet de réaliser des communications entre processus sous forme d'un flot continu d'octets. Dans ce TP, nous n'aborderons que la notion de tubes ordinaires (pipes). Un tube est matérialisé par deux entrées de la table des ouvertures de fichiers, une de ces entrées est ouverte en écriture (l'entrée du tube), l'autre en lecture (la sortie du tube). Création de tubes ordinaires Un processus ne peut utiliser que les tubes qu'il a créés lui-même par la primitive pipe ou qu'il a hérités de son père grâce à l'héritage des descripteurs à travers fork() et exec(). Lecture dans un tube On utilise l'appel système read. # include <unistd.h> int pipe (int p[2]); p[0] correspond au descripteur en mode lecture p[1] correspond au descripteur en mode écriture int nb_lu; /* nb de caractères lus */ nb_lu = read(p[0], buffer, TAILLE_READ); Mastère M2 IISA S1 7/12

Remarquer que la lecture se fait dans le descripteur p[0]. Ecriture dans un tube On utilise l'appel système write. int nb_ecrit; /* nb de caractères écrits */ nb_ecrit = write(p[1], buf, n); Exemple d utilisation des tubes ordinaires (fichier "prog.c") : # include <stdio.h> # include <unistd.h> int tube[2]; char buf[20]; main() pipe(tube); if (fork()) /* pere */ close (tube[0]); write (tube[1], "bonjour", 8); else /* fils */ close (tube[1]); read (tube[0], buf, 8); printf ("%s bien recu \n", buf); L exécution de ce programme ("prog") donne le résultat suivant : Exercice Ecrire le programme précédent, et l'exécuter. $ prog $ bonjour bien recu $ Exercice(s) Analyser les programmes donnés dans la suite, de sorte à comprendre leur fonctionnement. Si le temps est disponible, les écrire et les exécuter. /* * premier programme */ extern printf(); extern pipe(); extern write(); extern read(); extern close(); int main(void) int tab_numero_fd[2]; int xpipe; int valeur=12; Mastère M2 IISA S1 8/12

int valeur_lue; if ((xpipe = pipe(tab_numero_fd)) == -1) printf("pipe: error\n"); exit(1); write(tab_numero_fd[1], &va1eur, sizeof(int)); printf("apres write(1)\n"); valeur++; write(tab_numero_fd[1], &va1eur, sizeof(int)); printf("apres write(2)\n"); valeur++; read(tab_numero_fd[0], &valeur_lue, sizeof(int)); printf("apres read(l)\n"); printf("valeur_lue= %d\n", valeur_lue); write(tab_numero_fd[1], &va1eur, sizeof(int)); printf("apres write(3)\n"); valeur++; read(tab_numero_fd[0], &valeur_lue, sizeof(int)); printf("apres read(2)\n"); printf("valeur_lue= %d\n", valeur_lue); write(tab_numero_fd[1], &va1eur, sizeof(int)); printf("apres write(4)\n"); valeur++; write(tab_numero_fd[1], &va1eur, sizeof(int)); printf("apres write(5)\n"); read(tab_numero_fd[0], &valeur_lue, sizeof(int)); printf("apres read(3)\n"); printf("valeur_lue= %d\n", valeur_lue); read(tab_numero_fd[0], &valeur_lue, sizeof(int)); printf("apres read(4)\n"); printf("valeur_lue= %d\n", valeur_lue); read(tab_numero_fd[0], &valeur_lue, sizeof(int)); printf("apres read(5)\n"); printf("valeur_lue= %d\n", valeur_lue); close(tab_numero_fd[0]); close( tab_numero_fd[ 1]); return(0); /* * deuxième programme */ #define N 1 #define TRUE 1 #define FALSE 0 #define bits0a7 255 #include <signa1.h> #include <sys/wait.h> extern printf(); extern fork(); extern getpid(); extern getppid(); extern pause(); extern sleep(); extern usleep(); extern pipe(); extern write(); extern read(); extern close(); int numero; Mastère M2 IISA S1 9/12

int tabpid[n+1]; int pere_fils_fd[2]; int FILS = TRUE; void handler_sigusr2(int sig) if (numero == 0) FILS = FALSE; void handler_sigint(int sig) if (numero!= 0) kill(getppid(), SIGUSR2); exit(16 + numero); int main(void) int xfork, xwait, xpipe; int status; signal(sigusr2, handler_sigusr2); signal(sigint, handler_sigint); printf("pere: %d, GRAND-PERE: %d\n", getpid(), getppid()); if ((xpipe = pipe(pere_fils_fd)) == -1) printf("pipe: error\n"); exit(1); for (numero=1; numero<=n; numero++) if ((xfork = fork()) == -1) printf("fork: error\n"); exit(2); if (xfork == 0) break; else tabpid[numero] = xfork; printf("pere: fils: %d, PID: %d\n", numero, xfork); if (xfork == 0) int j; int valeur_lue; int somme = 0; while (TRUE) for (j=1;j<=5;j++) read(pere_fils_fd[o], &valeur_lue, sizeof(int)); printf("fils: valeur_lue\n"); somme = somme + valeur_lue; printf("fils: somme= %d\n", somme); somme = 0; else int valeur = 1; numero = 0; while (FILS) write(pere_fils_fd[l], &valeur, sizeof(int)); valeur++; usleep(300000); Mastère M2 IISA S1 10/12

while ((xwait = wait(&status))!= -1) printf("pere: fils %d termine', y= %X, x= %X\n", xwait, status & bitsoa7, (status>> 8) & bitsoa7); close(pere_fils_fd[o]); close(pere_fils_fd[1]); return 0; /* * troisième programme */ #define N 1 #define TRUE 1 #define FALSE 0 #define bitsoa7 255 #include <signal.h> #include <sys/waith> extern printf(); extern fork(); extern getpid(); extern getppid(); extern pause(); extern s1eep(); extern us1eep(); extern pipe(); extern write(); extern read(); extern close(); int numero; int tabpid[n+l]; int pere_fils_fd[2]; int fils_pere_fd[2]; int FILS = TRUE; void handler_sigusr2(int sig) if (numero == 0) FILS = FALSE; void handler_sigint(int sig) if (numero!= 0) kill(getppid(), SIGUSR2); exit(l6 + numero); int main(void) ( int xfork, xwait, xpipe; int status; signal(sigusr2, handler_sigusr2); signa1(sigint, handler_sigint); printf("pere: %d, GRAND-PERE: %d\n", getpid(), getppid()); if ((xpipe = pipe(pere_fils_fd)) = -1) printf("pipe: error\n"); exit(1); if ((xpipe = pipe(fils_pere_fd))) == -1) printf("pipe: error\nn); exit(1); for (numero=1; numero<=n; numero++) if ((xfork = fork()) == -1) printf("fork: error\n"); exit(2); if (xfork == 0) break; else tabpid[numero] = xfork; Mastère M2 IISA S1 11/12

printf("pere: fils: %d, PID: %d\n", numero, xfork); if (xfork == 0) int j; int valeur_lue; int somme = 0; while (TRUE) for (j=1;j<=5; j++) read(pere_fils_fd[o], &valeur_lue, sizeof(int)); printf("fils: valeur_lue\n"); somme = somme + valeur_lue; write(fils_pere_fd[1], &somme, sizeof(int)); somme = 0; else int i; int valeur = 1; int somme_lue; numero = 0; while (FILS) for (i=1; i<=5; i++) write(pere_fils_fd[1], &valeur, sizeof(int)); valeur++; read(fils_pere_fd[o], &somme_lue, sizeof(int)); printf("pere: somme= %d\n", somme_lue); usleep(300000); while ((xwait = wait(&status))!= -1) printf("pere: fils %d termine', y= %X, x= %X\n", xwait, status & bitsoa7, (status>> 8) & bitsoa7); close(pere_fils_fd[0]); close(pere_fils_fd[1]); close(fils_pere_fd[0]); close(fils_pere_fd[1]); return 0; Mastère M2 IISA S1 12/12