Upload
others
View
13
Download
4
Embed Size (px)
Citation preview
07/12/16 SEA 1
Systèmes d’Exploitations Avancés
Chapitre III-2 : Synchronisation et communication inter-processus avancés
Amine DHRAIEF
Mastère professionnel en Modélisation, Bases de Données et Intégration des Systèmes
ESEN, Univ. Manouba
07/12/16 SEA 2
Les moniteurs
Insuffisances des sémaphores
• Les sémaphores peuvent être utilisés pour résoudre à peu près n’importe quel problème d’exclusion mutuelle ou synchronisation . Mais, les sémaphores possèdent certains inconvénients:
– Mécanisme de bas niveau qui demande une discipline sévères dans la façon dont ils sont utilisés, sous peine d’erreurs: que se passe-t-il si on oublie d’indiquer un appel à UP? Ou si on effectue une action UP en trop?
– Mécanisme sans localité: un sémaphore doit être connu et accessible par tous les processus qui pourraient devoir l’utiliser doit être une variable globale tout le programme doit être examiné pour voir où et comment le sémaphore est utilisé
– Le rôle d’une opération UP ou DONW (exclusion mutuelle? synchronisation conditionnelle?) dépend du type de sémaphore, de la façon dont il est initialisé et manipulé par les divers processus → pas explicite
Les moniteurs comme solution altérnatives
• Solution alternative = Moniteur – Forme de module qui supporte, à l’aide de deux mécanismes indépendants,
l’exclusion mutuelle et la synchronisation conditionnelle
• Un moniteur est une collection – de procédures, – variables – et des structures de données – qui sont tous regroupés dans un module spéciale.
• Les processus peuvent appeler les procédures dans un moniteur chaque fois que ils veulent, mais ils ne peuvent pas accéder directement aux structures internes du moniteur à partir de procédures déclarées en dehors de la moniteur
Exemple d’un moniteur
monitor exampleinteger i;Condition c:Procedure producteur();{……}end;Procedure consommateur();{……}end;end monitor;
Exclusion mutuelle avec les moniteurs
● Les moniteurs ont une propriété importante qui les rend utiles pour la réalisation exclusion mutuelle: à un instant donnée, un seul processus peut être actif dans un moniteur.
● Les moniteurs sont une construction du langage programmation. Ce qui fait que le compilateur sait qu'ils sont spécifique: il gère les appels des procédures du moniteurs différemment des autres appels
Exclusion mutuelle avec les moniteurs
● En règle générale, lorsqu'un processus appelle une procédure du moniteur, les premières instructions déterminent si un autre processus est actuellement actif au sein du moniteur.
● Si c’est le cas, le processus appelant est suspendu jusqu’à ce que l’autre processus ait quitté le moniteur. Sinon, il peut y entrer.
● C’est au compilateur d’implémenter l’exclusion mutuelle sur les entrées du moniteurs
Exclusion mutuelle avec les moniteurs
● Malgré tout leur intérêt quant à l’exclusion mutuelle, les moniteurs ne suffisent pas.
● Il ne faut également faire en sorte que les processus se bloquent lorsqu’ils ne sont pas en mesure de poursuivre.
● Dans le contexte du producteur-consommateur, il est relativement aisée de placer tous les tests d’état du tampon (vide, plein) dans les procédures du moniteur,
● → Mais comment bloquer un producteur qui trouve un tampon plein ?
Exclusion mutuelle avec les moniteurs
● La solution consiste à introduire des variables conditionnelles prenant en charge deux opérations: wait et signal
● Lorsqu’une procédure du moniteur découvre qu’elle ne peut se poursuivre (tampon plein), elle effectue un wait sur une variable conditionnelle (full).
● Cette action provoque le blocage du processus appelant. Elle permet à un autre processus, qui s’était vu auparavant interdire l’entrée au moniteur, d’y entrer maintenant.
● Le consommateur peut réveiller son partenaire en envoyant un signal que son partenaire attend
Exclusion mutuelle avec les moniteurs
● Pour éviter que deux processus actifs ne se trouvent dans le moniteur simultanément, nous avons besoin d’une autre règle indiquant ce qui se passe à la suite d’un signal :
– Laisser le processus le plus récemment éveillé et suspendre l’autre
– Exiger du processus émettant un signal de quitter le moniteur immédiatement
Les variables conditionnelles & les moniteurs
● Les variables conditionnelles ne sont pas des compteurs– Elles n’accumulent pas les signaux pour une
utilisation ultérieur
– Si une variable conditionnelle est signalé alors que personne ne l’attend, le signal est perdu pour toujours
– En d’autre terme, wait doit intervenir avant signal
Producteur-Consommateur avec les moniteurs
monitor ProducteurConsommateur
condition full, empty;
Integer count;
procedure insert(item: integer);
begin
if count = N then wait (full)
Insert_item(item);
count:=count + 1;
If count = 1 then signal(empty)
end;
function remove: integer;
begin
if count = 0 then wait(empty)
remove=remove_item;
count:=count1;
if count = N 1then signal(full)
end;
Count:=0;
End monitor;
Producteur-Consommateur avec les moniteurs
Procedure producteur;
Begin
while true do
begin
item=produce_item;
ProducteurConsommateur.insert(item);
end
End;
Producteur-Consommateur avec les moniteurs
Procedure consommateur;
Begin
while true do
begin
item=ProducteurConsommateur.remove;
consume_item(item)
end
End;
Résolution du dîner des philosophes en utilisant les moniteurs
chopsticks
Résolution du dîner des philosophes en utilisant les moniteurs
07/12/16 SEA 18
Communication entre Processus
07/12/16 SEA 19
Définition● Les communications inter processus (Inter-Process Communication ou
IPC) regroupent un ensemble de mécanismes permettant à des processus concurrents (ou distants) de communiquer. Ces mécanismes peuvent être classés en trois catégories :
– Les outils permettant aux processus de s'échanger des données ;
– Les outils permettant de synchroniser les processus, notamment pour gérer l’accès à la section critique ;
– Les outils offrant directement les caractéristiques des deux premiers (ie : permettant d'échanger des données et de synchroniser des processus).
07/12/16 SEA 20
Définition
Méthodes:● Fichiers
● Signaux
● Socket
● File d’attends
● Pipe
● Named pipe
● Semaphore
● Shared memory
● Message passing
07/12/16 SEA 21
Les signaux : définition● Les signaux sont un outil de programme qui permet d’interrompre le
fonctionnement d’un processus sous UNIX et Linux.
● Le mécanisme des événements permet de notifier aux processus la production de différents événements exceptionnels qui peuvent être matériels ou logiciels.
● Un signal strictement déterminé est généré pour chaque événement.
● La gestion des signaux entre processus est peut-être la partie qui peut conduire aux dysfonctionnements les plus subtils, avec des bogues très difficiles à détecter de par leur nature fondamentalement intempestive.
07/12/16 SEA 22
Les signaux : principe● Le principe est a priori simple : un processus peut envoyer sous
certaines conditions un signal à un autre processus (ou à lui-même).
● Un signal peut être imaginé comme une sorte d'impulsion qui oblige le processus cible à prendre immédiatement (aux délais dus à l'ordonnancement près) une mesure spécifique.
● Le destinataire peut – soit ignorer le signal soit le capturer c'est-à-dire dérouter provisoirement
son exécution vers une routine particulière qu'on nomme GESTIONNAIRE DE SIGNAL
– soit laisser le système traiter le signal avec un comportement par défaut.
07/12/16 SEA 23
Les signaux : principe
● Il est important de toujours utiliser le nom symbolique du signal et non son numéro, car celui-ci peut varier d'un système à l'autre, voire selon la machine employée, même avec une version identique du noyau.
07/12/16 SEA 24
Les événements qui génèrent des signaux
● Erreurs: Une erreur survient en résultat de l’exécution incorrecte du programme et, pour cette raison, il ne peut pas se poursuivre.
– Non pas toutes les erreurs génèrent des signaux.
– Par exemple, les fonctions de bibliothèque renvoient le résultat -1 et n’engendrent pas de signal.
– Les signaux sont générés lors de la division par zéro ou en cas d’appel à une adresse invalide;
● Événements externes au processus: Les événements externes sont générés par le système d’entrée/sortie ou par d’autres processus.
– Ils englobent la réception de données d’entrée, l’écoulement d’un temporisateur, la terminaison d’un processus fils;
● Événements générés en résultat des requêtes explicites: A cet effet, on utilise des fonctions de bibliothèques spéciales, par exemple, kill(), dont la vocation est d’engendrer un signal
07/12/16 SEA 25
Les événements qui génèrent des signaux
Les signaux peuvent être générés:
● De manière synchrone: Les signaux synchrones relèvent des actions spécifiques du programme et sont livrés au processus au cours de ces actions. Par exemple, les signaux générés par des erreurs sont synchrones;
● De manière asynchrone: Les signaux asynchrones sont générés par des événements externes au processus auquel ils sont destinés. Ils sont livrés au processus à des moments imprévisibles au cours de son fonctionnement. Les signaux asynchrones sont générés encore par des requêtes explicites envers d’autres processus.
07/12/16 SEA 26
Numéro de signal● Chaque signal a un numéro affecté, qui est un entier positif,
et une constante de caractères qui est utilisée pour identifier le sens.
● Les signaux sont définis par des macros dans le fichier signal.h de manière suivante :
07/12/16 SEA 27
Numéro de signal● On distingue les suivantes classes de signaux de base, en fonction
du type des événements qu’ils répercutent:
– Signaux engendrés par des conditions matérielles déterminées
– Signaux engendrés par des conditions logicielles déterminées
– Signaux répercutant des messages d’entrée/sortie
– Signaux de gestion des processus
– Signaux de gestion des ressources
07/12/16 SEA 28
Signaux engendrés par des conditions matérielles
● SIGHUP : la communication avec le terminal d’utilisateur est interrompue, par exemple, interruption d’une communication de réseau ou téléphonique)
● SIGINT : interruption du programme à partir les touches Ctrl/C
● SIGQUIT : interruption du programme et affichage d’un cliché mémoire
● SIGALRM : indique l’écoulement d’un temporisateur
07/12/16 SEA 29
Signaux engendrés par des conditions logicielles
● SIGILL : instruction invalide – elle est générée lorsque le programme tente d’exécuter une instruction invalide ou privilégiée
● SIGSEGV : infraction au segment – le programme tente de s’adresser à la lecture ou à l’écriture en dehors de la zone de mémoire lui allouée
● SIGBUS : appel à une adresse invalide dans la mémoire, par exemple, appel d’après un pointeur, non aligné
● SIGFPE : erreur arithmétique fatale, par exemple, division par zéro et dépassement de la capacité
07/12/16 SEA 30
Autres...● Signaux répercutant des messages d’entrée/sortie. On compte parmi ces signaux:
– SIGIO (il est émis lorsque le descripteur de fichier est prêt à l’exécution d’entrée/sortie),
– SIGURG (il est émis lors de l’arrivée de données d’urgence à travers des socket);
● Signaux de gestion des processus:
– SIGKILL (cause la suppression d’un processus),
– SIGTERM (entraîne la terminaison du programme),
– SIGCHLD (généré lors de la terminaison d’un processus fils),
– SIGSTOP (entraîne l’arrêt d’un processus),
– SIGTSTP (arrêt interactif du processus),
– SIGCONT (signal de la continuation d’un processus suspendu);
● Signaux de gestion des ressources:
– SIGTTIN (un processus background tente de lire à partir du terminal),
– SIGTTOUT (un processus background tente d’écrire sur le terminal) etc.
07/12/16 SEA 31
SIGINT : INTerruption
SIGINT est envoyé à un processus afin de provoquer son interruption
Ce signal est émis vers tous les processus du groupe en avant-plan lors de la frappe d'une touche particulière du terminal : la touche d'interruption.
Sur les claviers de PC sous Linux, ainsi que dans les terminaux Xterm, il s'agit habituellement de Contrôle-C.
07/12/16 SEA 32
SIGKILL● SIGKILL est l'un des deux seuls signaux (avec SIGSTOP) qui ne puisse ni être capturé
ni être ignoré par un processus. A sa réception, tout processus est immédiatement arrêté.
● C'est une garantie pour s'assurer qu'on pourra toujours reprendre la main sur un programme.
● Le seul processus qui ne puisse pas recevoir SIGKILL est init, le processus de PID 1.
● SIGKILL est traditionnellement associé à la valeur 9, d'où la célèbre ligne de commande « kill -9 xxx» , équivalente à « Kill -KILL xxxx ». On notera que l'utilisation de SIGKILL doit être considérée comme un dernier recours. le processus ne pouvant se terminer proprement. On préférera essayer par exemple SIGQUIT ou SIGTERM auparavant.
07/12/16 SEA 33
SIGKILL● Notons qu'un processus zombie n'est pas affecté par
SIGKILL (ni par aucun autre signal d'ailleurs).
● Si un processus est stoppé. il sera relancé avant d'être terminé par SIGKILL.
● Le noyau lui-même n'envoie que rarement ce signal. C'est le cas lorsqu'un processus a dépassé sa limite de temps d'exécution, ou lors d'un problème grave de manque de place mémoire.
07/12/16 SEA 34
Signaux SIGSTOP, SIGCONT
● SIGSTOP est le deuxième signal ne pouvant être ni capturé ni ignoré, comme SIGKILL. – Il a toutefois un effet nettement moins dramatique que ce dernier,
puisqu'il ne s'agit que d'arrêter temporairement le processus visé.
– Celui-ci passe à l'état stoppé.
● Le signal SIGCONT a l'effet inverse ; il permet de relancer un processus stoppé. – Si le processus n'est pas stoppé ce signal n'a pas d'effet.
– Le redémarrage a toujours lieu, même si SIGCONT est capturé par un gestionnaire de signaux de l'utilisateur ou s'il est ignoré.
07/12/16 SEA 35
SIGTERM● Ce signal est une demande «gentille» de terminaison d'un
processus.
● Il peut être ignoré ou capturé pour terminer proprement le programme en ayant effectué toutes les tâches de nettoyage nécessaires. Traditionnellement numéroté 15, ce signal est celui qui est envoyé par défaut par la commande /bin/kill.
● SIGTERM est défini par Ansi C et Posix.1. Par défaut il termine le processus concerné.
07/12/16 SEA 36
SIGQUIT
● Comme SIGINT, ce signal est émis par le pilote de terminal lors de la frappe d'une touche particulière : the QUIT character
● SIGQUIT termine par défaut les processus qui ne l'ignorent pas et ne le capturent pas, mais en engendrant en plus un fichier d'image mémoire (core).
07/12/16 SEA 37
L’action des signaux● Après avoir été généré, un signal donné est délivré au
processus, auquel il est destiné. En recevant le signal, le processus exécute une action spécifique pour le signal donné.
● Cette action est strictement fixée pour les signaux SIGKILL et SIGSTOP, et pour les autres signaux, elle est au choix et peut être :– Une action par défaut– Ignorer le signal– Fonction spéciale de traitement du signal (signal handler).
07/12/16 SEA 38
Action par défaut des signaux● Chaque type de signal a son action par défaut.
● Pour la plupart des signaux, cette action est de suspendre l’exécution du processus.
● Pour certains types de signaux, le comportement par défaut est de ne rien faire, c’est-à-dire, ils ignorent le signal.
● Lorsque le signal suspend l’exécution d’un processus, le processus parent peut déterminer la cause de la terminaison par le test du code de terminaison , qui est obtenu par les appels de système wait() ou waitpid().
● Le code de terminaison comporte de l’information sur le signal
07/12/16 SEA 39
Émission de signaux sous Linux● Pour envoyer un signal à un processus, on utilise l'appel-système kill( ),
qui est particulièrement mal nommé car il ne tue que rarement l'application cible.
● Cet appel système est déclaré ainsi int kill (pid_t pid, int numero_signal);
– Le premier argument correspond au PID du processus visé, et le second au numéro du signal à envoyer.
● Rappelons qu'il est essentiel d'utiliser la constante symbolique correspondant au nom du signal et non la valeur numérique directe.
– Il existe une application /bin/kill qui sert de frontal en ligne de commande à l'appel système kill( ).
07/12/16 SEA 40
Émission de signaux sous Linux
● /bin/kill prend en option sur la ligne de commande un numéro de signal précédé d'un tiret « - » et suivi du ou des PID des processus à tuer.
● Le numéro de signal peut être remplacé par le nom symbolique du signal, avec ou sans le préfixe SIG.
07/12/16 SEA 41
Émission de signaux sous Linux● En fait, le premier argument de l'appel-système kill( ) peut prendre diverses
valeurs : – S'il est strictement positif, le signal est envoyé au processus dont le PID correspond à cet
argument.
– S'il est nul, le signal est envoyé à tous les processus du groupe auquel appartient le processus appelant.
– S'il est négatif, sauf pour -1, le signal est envoyé à tous les processus du groupe dont le PGID est égal à la valeur absolue de cet argument.
– S'il vaut -1, POSIX indique que le comportement est indéfini. Sous Linux, le signal est envoyé à tous les processus sur le système, sauf au processus init (PID=1) et au processus appelant. Cette option est utilisée, par exemple dans les scripts de shutdown pour tuer les processus avant de démonter les systèmes de fichiers et d'arrêter le système
07/12/16 SEA 42
Émission de signaux sous Linux● En cas du succès d’exécution, la fonction kill() renvoie
la valeur 0, dans le cas contraire, le signal n’est pas émis et la fonction renvoie la valeur -1.
● Le code de la cause concrète du défaut de l’exécution de kill() est écrit dans la variable de système errno.– La cause d’une terminaison d’avarie de kill() peut s’avérer le
réglage d’un signal ou d’un processus qui n’existent pas sous Linux.
– Si un signal est envoyé à un groupe de processus, la fonction se termine avec succès, si au moins l’un d’entre eux reçoit le signal.
07/12/16 SEA 43
Émission de signaux sous Linux
● Exemple– kill(49, SIGKILL) – émet le signal SIGKILL vers un
processus dont l’identificateur est 49;
– kill(0, SIGFPE) – le signal SIGFPE sera émis vers tous les processus du groupe, si une erreur se produit au cours de l’exécution d’une opération arithmétique ;
– kill(getpid(), SIGALRM) – le processus émet le signal SIGALRM sur lui-même
07/12/16 SEA 44
Réception des signaux avec l'appel-système signal( )
● Un processus peut demander au noyau d'installer un gestionnaire pour un signal particulier, c'est-à-dire une routine spécifique qui sera invoquée lors de l'arrivée de ce signal.
● Le processus peut aussi vouloir que le signal soit ignoré lorsqu'il arrive, ou laisser le noyau appliquer le comportement par défaut (souvent une terminaison du programme).
07/12/16 SEA 45
Réception des signaux avec l'appel-système signal( )
● L’appel de système signal() est définie la fonction qui doit traiter un signal donné, dès qu’il est délivré au processus. – int *signal (int sig, void (*func)())
● Le premier argument un numéro de signal. – Bien entendu, il faut utiliser la constante symbolique correspondant
au nom du signal, jamais la valeur numérique directe.
● Le second argument est un pointeur sur la routine qu'on désire installer comme gestionnaire de signal.
07/12/16 SEA 46
Réception des signaux avec l'appel-système signal( )
● Nous allons pouvoir installer notre premier gestionnaire de signal. Nous allons tenter de capturer tous les signaux.
– Bien entendu, signal( ) échouera pour SIGKILL (9) et SIGSTOP (19).
● Pour tous les autres signaux, notre programme affichera le PID du processus en cours, suivi du numéro de signal et de son nom.
● Il faudra disposer d'une seconde console (ou d'un autre Xterm) pour pouvoir tuer le processus à la fin.
07/12/16 SEA 47
Réception des signaux avec l'appel-système signal( )
07/12/16 SEA 48
Réception des signaux avec l'appel-système signal( )
07/12/16 SEA 49
Communications classiques entre processus
● Dès qu'une application dépasse un certain degré de complexité pour ce qui concerne les fonctionnalités indépendantes, on peut être tenté de la scinder en plusieurs entités distinctes, sous forme de processus par exemple.
● Prenons le cas d'une base de données offrant des possibilités de consultation par l'intermédiaire de connexions TCP/IP. – On peut diviser cette application en plusieurs tâches indépendantes.
– Le noyau principal s'occupe de superviser la base de données elle même, en gérant notamment les problèmes d'accès simultanés.
– Un second module assure l'écoute des demandes de connexion et leurs initialisations.
– Enfin, on peut imaginer disposer d'une multitude de copies d'un dernier module, chargé du déroulement complet de la liaison avec le client, y compris l'interface de dialogue.
07/12/16 SEA 50
Communications classiques entre processus
● Pour construire ce genre de système, plusieurs options se présentent – Un seul processus s'occupe de tous les travaux. On conserve en mémoire une
copie des données nécessaires au suivi de la connexion pour chaque client. Le processus bascule d'une fonction à l'autre au gré des requêtes grâce à l'appel-système select( )
– On utilise un système à base de threads, l'accès aux informations globales de la base de données devant être strictement régi par des mutex. Les données propres à chaque connexion sont conservées dans des variables locales de la routine centrale du thread de communication.
– On scinde l'application en plusieurs processus, le noyau principal restant à l'écoute des requêtes de ses fils. Chaque module de communication est représenté par un processus indépendant doté de ses données propres, dialogue avec le client sur une liaison réseau et avec le noyau central par l'intermédiaire de l'une des différentes méthodes que nous allons étudier.
07/12/16 SEA 51
Communications classiques entre processus
● Finalement, chacune de ces méthodes a des avantages et des défauts :– Le processus unique est plus facilement portable sur d'autres systèmes
qu'Unix mais, en contrepartie, l'écriture et la maintenance de cette application sont plus compliquées car des fonctionnalités sans rapport entre elles sont regroupées dans le même logiciel.
– La combinaison de plusieurs threads offre une grande souplesse et une bonne portabilité, mais l'indépendance des modules n'est qu'illusoire. Lors d'une évolution du logiciel initial, l'accès à des données globales peut engendrer subitement des bogues difficiles à découvrir.
– La division en plusieurs processus permet d'avoir des modules vraiment indépendants, devant simplement se plier à une interface bien définie. Par contre, le système est dépendant de l'architecture Unix, et la création d'un nouveau processus pour chaque connexion peut parfois être pénalisante.
07/12/16 SEA 52
Communications classiques entre processus
● Nous allons examiner le moyen de communication le plus simple pour deux processus issus de la même application (père et fils, ou frères) : les tubes.
● Il y a également des cas où l'ensemble applicatif repose sur plusieurs logiciels totalement indépendants. Ces programmes doivent disposer d'un autre moyen de communication puisque les tubes ne leur sont plus adaptés. Linux offre alors le concept de tubes nommés, qui sont conçus pour cette situation
● Nous nous limitons pour le moment aux communications entre deux processus résidant dans le même système. Lorsqu'on veut faire dialoguer des logiciels se trouvant sur des stations différentes, il faut employer des méthodes traitant de la programmation réseau (mais qui ne diffèrent par ailleurs pas beaucoup des principes étudiés ici).
07/12/16 SEA 53
Les Tubes
07/12/16 SEA 54
Les tubes
● Un tube de communication est un tuyau dans lequel un processus écrit des données qu'un autre processus peut lire. Le tube est créé par l'appel-système pipe( ), déclaré dans <unistd.h>:– int pipe (int descripteur[2]);
● Lorsqu'elle réussit, cette fonction crée un nouveau tube au sein du noyau et remplit le tableau passé en argument avec les descripteurs des deux extrémités.
● Étant donné que le langage C passe les arguments du type tableau par référence, la routine pipe( ) reçoit un pointeur sur la table et peut donc écrire dans les deux emplacements réservés. – Les descripteurs correspondent respectivement à la sortie et à l'entrée du tube.
07/12/16 SEA 55
Les tubes● Le tube est entièrement sous le contrôle du noyau. Il réside en mémoire (et
pas sur le disque) et le processus reçoit les deux descripteurs correspondant à l'entrée et à la sortie du tube. – Le descripteur d'indice 0 est la sortie du tube, il est ouvert en lecture seule.
– Le descripteur 1 est l'entrée ouverte en écriture seule.
● Nous observons en effet que les tubes sont des systèmes de communication unidirectionnels. Si on désire obtenir une communication complète entre deux processus, il faut créer deux tubes et les employer dans des sens opposés.
● Dans notre premier exemple, nous allons simplement créer un tube, écrire des données dedans, lire son contenu et vérifier que les informations sont identiques
07/12/16 SEA 56
07/12/16 SEA 57
Les tubes
07/12/16 SEA 58
Les tubes● Utiliser un tube pour transférer des données au sein du même processus ne
présente aucun intérêt.
● Aussi nous allons utiliser ce mécanisme pour faire communiquer deux processus (ou plus).
● Pour cela, nous devons invoquer l'appel-système fork( ) après avoir créé le tube.
● Si celui-ci doit aller du processus père vers le fils, le père ferme son descripteur de sortie de tube, et le fils son descripteur d'entrée.
● Nous expliquerons plus tard pourquoi la fermeture des extrémités inutilisées est importante
07/12/16 SEA 59
Les tubes
07/12/16 SEA 60
Les tubes
07/12/16 SEA 61
Les tubes● La différence avec l'exemple précédent est que, en plus de créer un pipe, notre
processus crée un fils. 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]").
● Chacun des processus ayant été créé après l'appel à pipe(), chacun aura accès aux deux cotés du tube (lecture/écriture). – Chacun devra donc commencer par fermer le coté qu'il n'utilise pas ; en particulier le coté d'écriture pour
le processus lecteur. – Cela permettra plus tard au noyau, lorsque le processus écrivain aura fini son travail et fermé son coté
d'écriture, de détecter que le tube n'a plus aucun processus au coté d'écriture ouvert et d'envoyer alors un caractère "EOF" (-1) à tout processus lecteur éventuel du tube.
07/12/16 SEA 62
Les tubes● Nous remarquons que ce système est semblable au principe du pipe des
shells, qui permet grâce au caractère « | » de diriger la sortie standard d'un processus vers l'entrée standard d'un autre.
● Pour illustrer ce principe, nous allons créer un programme qui prend deux commandes en arguments et qui les exécute en redirigeant la sortie standard de la première vers un tube connecté à l'entrée standard de la seconde.
● Pour lancer les commandes nous utilisons fork( ) pour dissocier deux processus, le fils exécutant la première commande, et le père la seconde. – Pour éviter d'avoir à analyser les chaînes de caractères pour séparer les commandes
de leurs arguments, nous faisons appel à la fonction system( ).
– Nous utilisons l'appel-système dup2( ) remplacer les flux stdin et stdout des processus par les extrémités du tube
07/12/16 SEA 63
Les tubes
07/12/16 SEA 64
Les tubes
07/12/16 SEA 65
Les tubes
07/12/16 SEA 66
The END