La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Systèmes d’exploitation

Présentations similaires


Présentation au sujet: "Systèmes d’exploitation"— Transcription de la présentation:

1 Systèmes d’exploitation
La communication inter-processus

2 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)

3 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

4 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

5 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 !

6 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 !

7 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 */

8 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 !

9 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.

10 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 :

11 Problème du producteur et du consommateur (2)
#define N /* 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 */

12 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 !

13 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

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

15 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

16 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)

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

18 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 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

19 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 !

20 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 */


Télécharger ppt "Systèmes d’exploitation"

Présentations similaires


Annonces Google