Systèmes d’exploitation

Slides:



Advertisements
Présentations similaires
Module Systèmes d’exploitation
Advertisements

Contrôle de la concurrence
GEF 435 Principes des systèmes d’exploitation
Synchronisation de Processus
Le Concept du programme enregistré
Synchronisation des processus père - fils
Module Systèmes d’exploitation
Module Systèmes dexploitation Chapitre 6 Communication Interprocessus Partie III École Normale Supérieure Tétouan Département Informatique
GEF 435 Principes des systèmes d’exploitation
GEF 435 Principes des systèmes dexploitation Communication Interprocessus (CIP) II (Tanenbaum 2.3)
GEF 435 Principes des systèmes dexploitation Communication Interprocessus (CIP) III (Tanenbaum 2.3)
TP 7.1 synchronized et join Écrire un programme Java qui crée 1000 threads et maintient un compteur nb du nombre de threads créés jusque-là. Le thread.
Synchronisation des Processus
(Classes prédéfinies – API Java)
Chapitre 3 Coopération et synchronisation par variables partagées
Chapitre 2 Processus & Threads
Exécutif Temps réel. Limitation des système classiques Rappels Mise en œuvre lourde des communications entre processus Problème de prédictibilité avec.
Le Concept du programme enregistré
Exécution en ordre partiel Une fois les instructions renommées, les seules dépendances qui subsistent entre instructions registre-registre sont les dépendances.
Récursivité.
Rappel sur la synchronisation des processus
Synchronisation et communication entre processus
Atomicité Transactions Atomiques Recouvrement à Base de Journal
Système d’exploitation
Algorithmique et Programmation
EPID-CPI-ISAIP Philippe Bancquart - mise à jour 24/02/ page 1 Cours de CPI Philippe Bancquart CPI 2005.
Allocation de mémoire Allocation de mémoire.
Architecture introduction.
Test et débogage Tests unitaires. Gestion d’erreurs. Notion d’état, de pré-condition et de post-condition. Assertion. Traces de programme. Débogueur et.
Module 51 Module 5 - Synchronisation de Processus (ou threads, ou fils ou tâches) Module 5 - Synchronisation de Processus (ou threads, ou fils ou tâches)
Les Fonctions. Définir une fonction Sections de code indépendantes que lon peut appeler à nimporte quel moment et dans nimporte quel ordre. Bout de code.
Introduction à la programmation I Fonctions Structures de contrôle Structures de données (arrays simples et indexés) Variables locales et globales.
Principes de programmation (suite)
Chapitre XI Gestion des erreurs et exceptions. 2 La gestion des erreurs et exceptions De nombreux problèmes peuvent survenir pendant lexécution dun programme:
Programmation concurrente
Chapitre 6 (Silberchatz)
LIFI-Java 2004 Séance du Jeudi 9 sept. Cours 1. La notion de langage Décrire une tâche à effectuer –programme Écrire à un haut niveau –facile pour lutilisateur.
Chapitre 3 Interblocages 3.1. Ressources
Chapitre 6 : Synchronisation des processus et des fils
Synchronisation Classique
Synchronisation de Processus
Structures de données IFT-2000 Abder Alikacem La récursivité Département d’informatique et de génie logiciel Édition Septembre 2009.
Qu’est-ce qu’un système d’exploitation ?
L ’Ordonnancement Ordonnancement.
RAPPEL Qu’est ce qu’une structure de contrôle itérative ?
Systèmes de gestion de bases de données NFP 107 Les techniques du contrôle de concurrence Philippe Rigaux
Gestion de Fichiers GF-3: Structures d’Enregistrements, Acces Sequentiel et Direct, Manipulation de classes en C++ (Base sur des segments des Chapitres.
Systèmes d’exploitation
JavaScript Nécessaire Web.
Réunions Lync Participer à une réunion Lync Aide-mémoire Lync 2013
SYSTÈME D’EXPLOITATION I
Module 8 : Surveillance des performances de SQL Server
Gestion de processus Corrigé TD 1 EFREI I
Travailler avec des processus
GESTION ET TRAITEMENT DES ERREURS
8PRO100 Éléments de programmation Comment répéter plusieurs fois une séquence d’instructions.
NOTIONS DE BASE DES SYSTÈMES TEMPS-RÉEL Sujets Concepts de processus/thread concurrents –Windows NT et la programmation temps réel Lectures: Chapitres.
Interactions entre Processus
Surveiller et résoudre le conflit de verrouillage
Tutorat en bio-informatique
Programmation Système et Réseau
Cours LCS N°4 Présenté par Mr: LALLALI
Introduction au langage C : Structures de contrôle 1 ère année Génie Informatique Dr Daouda Traoré Université de Ségou
8PRO107 Éléments de programmation Les adresses et les pointeurs.
Les Processus.
Chapitre 4 La représentation des nombres.
Systèmes d’exploitation Processus conclusion Modèle conceptuel de processus Pour masquer les effets des interruptions, les SE fournissent un modèle conceptuel.
Algorithmique Boucles et Itérations
Java Réalisé par: Mouna POKORA. PLAN: Définition : Historique: Caractéristiques: un langage orienté objet: un langage interprété : un langage portable:
1 UNIX AVANCE Yves PAGNOTTE – Janvier – PROCESSUS ET RESSOURCES.
Transcription de la présentation:

Systèmes d’exploitation La communication inter-processus

Introduction Nécessité d’échanger des informations Dans les SE, les processus peuvent partager un espace de données où chacun peut lire ou écrire (ex : un fichier) Le type ou l’emplacement de cet espace mémoire partagé n’influe ni sur la nature de la communication ni sur les problèmes qui en découlent Exemple : « spool » d’impression un nombre d’emplacements (0,1,2, …, n) contenant chacun un fichier à imprimer 2 variables in et out pointent sur le prochain emplacement libre et le prochain fichier à imprimer Supposons que les positions de 0 à 3 soient vides et celles de 4 à 6 soient occupées Un processus A récupère in et est ensuite interrompu par l’ordonnanceur, un processus B veut également imprimer, il récupère in, place son fichier et la main est de nouveau rendu à A, qui place son fichier  le fichier de B n’est jamais imprimé ! Les situations où plusieurs processus lisent ou écrivent des données partagées et où le résultat dépend de l’ordonnancement des processus sont qualifiés d’accès concurrents (race conditions)

Sections critiques Pour éviter les conflits d’accès, il faut trouver un moyen d’interdire la lecture ou l’écriture des données partagées à plus d’un processus à la fois  Exclusion mutuelle (EM)  différentes primitives pour assurer l’exclusion mutuelle Le choix de ces primitives est important pour la conception d’un SE La partie du programme où se produit le conflit d’accès est appelé une section critique (SC) Le problème des conflits d’accès est résolu si on peut assurer que 2 processus sont jamais en section critique en même temps Cette condition est suffisante, mais elle ne permet pas de faire coopérer correctement et efficacement des processus parallèles partageant des ressources 4 conditions sont nécessaires : 2 processus ne peuvent être en même temps en SC Aucune hypothèse ne doit être faite sur les vitesses relatives des processus Aucun processus suspendu en dehors d’une SC ne doit bloqué les autres processus Aucun processus ne doit attendre trop longtemps avant d’entrer en SC

Masquage des interruptions On masque les interruptions avant d’entrer en SC Solution la + simple Inconvénients : Oublie de restauration des interruptions  fin du système Cas de plusieurs processeurs Utilisation par le noyau pour des instructions délicates (ex : maj de la liste des processus prêts) Technique utile dans le noyau, mais inapproprié pour des processus utilisateurs

Variables de verrouillage Moyen logiciel Considère une variable booléenne (le verrou) partagée (0 la SC est libre, 1 un processus est en SC) Un processus doit tester la valeur de cette variable avant d’entrer en SC Inconvénient : identique au spool Processus interrompu juste avant de mettre la valeur à 1 Idée : lire une première fois le verrou, puis une seconde juste avant de modifier sa valeur  repousser le problème !

L’alternance PROCESSUS A : for(;;) { while (tour); /* attente */ SC tour=1; SNC /*(section non critique)*/ } PROCESSUS B : for(;;) { while (!tour); /* attente */ SC tour=0; SNC /*(section non critique)*/ } La variable tour (initialement à 0) mémorise le tour du processus qui doit entrer en SC Le test répété pour détecter l’apparition d’une valeur est appelé attente active Cette attente doit en général être évité car elle consomme du temps processeur À n’utiliser que lorsque l’on suppose que le temps d’attente sera court ! Inconvénient : grande différence de vitesse entre les 2 processus proc A entre et sort de SC proc B entre et sort de SC, il est en SNC et a traitement très long à réaliser proc A termine sa SNC, entre et sort de SC, et termine de nouveau sa SNC  proc A est bloqué en dehors de sa SC : contraire à la règle 3 Nécessité d’une alternance stricte !

Solution de Peterson Dekker fut le premier à proposer une solution logicielle au problème de l’exclusion mutuelle Solution basée sur la combinaison de l’alternance, de verrous et d’avertissement Solution TRÈS compliquée et jamais utilisée en pratique En 1981, Peterson propose une solution bien plus simple rendant obsolète celle de Dekker #define FALSE 0 #define TRUE 1 #define N 2 /* nombre de processus */ int tour; /* à qui le tour */ int interesse[N]; /* initialement à FALSE */ void entrer_SC(int proc) /* numéro du processus 0 ou 1 */ { int autre=1-proc; /* l’autre processus */ interesse[proc]=TRUE; /* indiquer que l’on est intéressé */ tour=proc; /* positionner le drapeau */ while ((tour==proc)&&(interesse[autre]==TRUE)); } void quiter_SC(int proc) /* processus quittant la SC 0 ou 1 */ interesse[proc]=FALSE; /* indication de sortie de SC */

Instruction TSL Solution nécessitant l’aide du matériel De nombreux ordinateurs ont une instruction TEST AND SET LOCK (TSL) Cette instruction : Charge un mot mémoire dans un registre Met une valeur non nulle à cette adresse Ces opérations de lecture et d’écriture du mot étant garanties indivisibles (atomiques) Solution : entrer_SC: tsl registre, flag | copier flag dans registre et met flag à 1 cmp registre,#0 | flag égal à 0 ? jnz entrer_SC | si différent de 0 (verrou mis), boucler ret | retour à l’appelant ; entrée en SC quitter_SC: mov flag,#0 | mettre 0 dans flag ret | retour à l’appelant ; Solution nécessitant l’aide du matériel Solution de Peterson et TSL : si 1 processus triche, l’exclusion mutuelle échoue !

Primitives sleep et wakeup Solution de Peterson et TSL correctes mais se basent tous les deux sur l’attente active ! Consommation de temps CPU ! Mais aussi des résultats imprévus : 2 processus H et B avec des priorités d’ordonnancement tel que si H est exécuté dès qu’il est prêt A un moment donné, B est en SC et H passe dans l’état prêt H effectue donc une attente active B ne peut plus être sélectionné puisque H est prioritaire H reste en permanence dans sa boucle et B ne peut plus sortir de sa SC ! Problème appelé inversion de priorité  des primitives de communication qui bloquent un processus Les + simples : sleep et wakeup sleep suspend l’appelant en attendant qu’un processus le réveil wakeup a un seul paramètre : le processus à réveiller sleep et wakeup ont chacun, en alternance, un paramètre qui est l’adresse mémoire utilisée pour faire correspondre les sleep et wakeup.

Problème du producteur et du consommateur (1) 2 processus partagent une mémoire tampon fixe Le producteur met des informations en mémoire Le consommateur les retire Problèmes : le producteur veut mettre des infos alors que la mémoire est pleine le producteur devra dormir en attendant d’être réveillé par le consommateur lorsque ce dernier aura retiré des infos De même lorsque le consommateur veut retirer de l’info alors que le tampon est vide, il devra dormir en attendant que le producteur y mette quelque chose et le réveille Une solution simple :

Problème du producteur et du consommateur (2) #define N 100 /* Taille du tampon */ int cpt=0; /* nb objets dans le tampon */ void producteur(void) { for(;;) /* boucle infinie */ { produire_objet(&objet); /* produire l’objet suivant */ if (cpt==N) sleep(); /* si tampon plein, dormir */ mettre_objet(objet); /* mettre l’objet dans tampon */ cpt++; /* inc. nb objets dans tampon */ if (cpt==1) wakeup(consommateur); /* réveiller le consommateur */ } } void consommateur(void) { if (cpt==0) sleep(); /* si tampon vide, dormir */ retirer_objet(&objet); /* retirer l’objet du tampon */ cpt--; /* déc. nb objets dans tampon */ if (cpt==N-1) wakeup(producteur); /* réveiller le producteur */ consommer_objet(objet); /* exploiter l’objet */

LES 2 PROCESSSUS DORMIRONT DONC POUR TOUJOURS ! Problème du producteur et du consommateur (3) Solution simple mais incorrect ! Problème vient de l’accès libre à la variable cpt Mémoire tampon vide, conso vient de trouver 0 comme valeur de cpt et l’ordonnanceur l’interrompt Le producteur à la main, il met un objet, il constate que le compteur vaut 1 et fait donc appel à wakeup Le signal wakeup est perdu car le consommateur n’est pas en train de dormir ! Lorsque le consommateur sera relancé, il testera la valeur de cpt qu’il avait lue avant d’être suspendu, trouvera 0 et se mettra en sommeil Le producteur finira par remplir la mémoire tampon et ira lui aussi dormir LES 2 PROCESSSUS DORMIRONT DONC POUR TOUJOURS ! Problème vient que tout signal wakeup, envoyé à un processus qui ne dort pas est perdu Solution : ajouter un bit de réveil en attente qui serait positionné lorsqu’un wakeup est envoyé à un processus déjà réveillé ; plus tard lorsque le processus voudra dormir, le bit sera remis à 0 mais le processus restera éveillé Dans cet exemple simple, le bit de réveil permet de se sortir d’affaire ; mais on peut facilement imaginer des situations à plusieurs processus où un seul bit ne suffit pas  un 2ème bit, voire même 32 ou 64 mais cela ne fera que repousser le problème !

Les sémaphores Telle était la situation en 1965, lorsque Dijkstra suggéra l’emploi d’une variable entière pour compter le nombre de réveils en attente Il introduisit un nouveau type de variables : les sémaphores Un sémaphore à la valeur 0 si aucun réveil n’a été mémorisé et une valeur positive s’il y a un ou plusieurs réveils en attente 2 opérations sur les sémaphores P et V (généralisations de sleep et wakeup) L’opération P : décrémente la valeur d’un sémaphore si cette dernière est supérieure à 0 (cad qu’elle consomme un wakeup mémorisé) Si la valeur du sémaphore est 0, le processus est mis en attente Le test du sémaphore, le changement de sa valeur, et la mise en attente sont effectuées en une seule opération atomique (l’atomicité est ici primordiale !) L’opération V : incrémente la valeur du sémaphore Si un ou plusieurs processus étaient en attente sur ce sémaphore (bloqués par un P), l’un d’entre eux est choisi par le système pour terminer son appel à P A la suite d’une opération V sur un sémaphore qui bloquait des processus, la valeur du sémaphore est toujours 0, mais il y a un processus de moins en attente V est également une opération indivisible mais une opération non bloquante

Solution du problème producteur/consommateur au moyen des sémaphores EN TD

Les compteurs d’événements Introduits par Reed et Kanodia en 1979 Définition d’une variable particulière E appelée compteur d’événements 3 événements sont définis pour E : Read(E) : donne la valeur courante de E Advance(E) : incrémente E de 1 de manière atomique Await(E,v) : attend que E atteigne ou dépasse la valeur v Solution du problème producteur/consommateur à l’aide des compteurs d’événements : EN TD

Les moniteurs Introduits par Hoare (1974) comme primitive de synchronisation de haut niveau Un moniteur est un ensemble de procédures, de variables et de structures de données regroupées dans un module spécial Les processus peuvent à tout moment faire appel aux procédures du moniteur mais ils ne peuvent pas accéder à la structure interne des données du moniteur à partir de procédures externes Un seul processus peut être actif dans un moniteur à un instant donné L’EM est donc garantie au niveau des entrées dans le moniteur (assurée par le compilateur qui doit faire la différence entre les procédures internes ou externes au moniteur) Afin de bloquer les processus, il faut introduire des variables de condition, ainsi que deux opérations wait et signal : Si une procédure du moniteur ne peut poursuivre son exécution, elle effectue un wait sur une variable conditionnelle Cette action entraîne le blocage du processus et autorise un autre processus à entrer dans le moniteur Cet autre processus peut réveiller le processus endormi en effectuant l’opération signal sur la même variable conditionnelle Un processus qui effectue un signal doit quitté immédiatement le moniteur (Brinch Hansen, 1975) Si un signal concerne une variable de condition sur laquelle plusieurs processus sont en attente, seul l’un d’entre eux, choisi par l’ordonnanceur, est réactivé Si une variable de condition reçoit un signal alors qu’aucun processus n’attend sur cette variable, le signal est perdu Automatisation de l’EM => programmation parallèle beaucoup plus sure Inconvénient : Seuls quelques rares langages les implémentent (ex : Concurrent Euclid)

Solution du problème producteur/consommateur au moyen des moniteurs EN TD

L’échange de messages Problème des moniteurs et des sémaphores : utilisent une mémoire partagée Solution : l’échange de messages à l’aide de 2 appels systèmes : send(destination,&message) receive(&source,&message) [peut être bloquant, source=ANY provenance non précisé] Possibilités de communication entre processus sur des machines distinctes à travers le réseau Problème de pertes de messages  procédures d’acquittement Problème de l’authentification des processus (processus@machine) Problème de sécurité (ex : serveur de fichiers confidentiels comment savoir que l’on n’a pas à faire à un processus imposteur) Problème de performance (ex: lenteur du réseau) Beaucoup de problèmes MAIS seule solution lorsqu’il n’y a pas de mémoire partagée Solutions : cf. cours systèmes distribués

Autres méthodes Différents auteurs ont introduits d’autres méthodes de communication inter-processus : Reed et Kanodia (79) : les séquenceurs Campbell et Habermann (74) : path expressions Atkinson et Hewitt (79) : les sérialiseurs Au fil des ans, chaque méthode fait de nouveaux adeptes et chacun revendique sa méthode comme la meilleure En fait, pour un système à un seul processeur, on montre facilement que toutes ces méthodes sont équivalentes !

Utilisation des sémaphores pour réaliser des moniteurs typedef int semaphore semaphore mutex = 1; /* pour contrôler l’accès au moniteur */ void entrer_moniteur(void)/* exécuté en entrant dans le moniteur */ { P(mutex); /* 1 seul processus à la fois dans le moniteur */ } void sortir_moniteur(void)/* quitter normalement le moniteur */ V(mutex); void signal(semaphore c) /* signal sur c et sortie du moniteur */ { /* c = variable de condition */ V(c); /* libérer processus en attente sur c */ sortie_moniteur(); /* on quitte toujours le moniteur apres un signal */ void wait(semaphore c) /* dormir sur une condition */ { /* C = condition concernée */ V(mutex); /* permettre à un autre processus d’entrer */ P(c); /* dormir sur la condition */