CEG4566/CSI4541 Conception de systèmes temps réel. Chapitre 8 - Communication et synchronisation dans les systèmes temps réel



Documents pareils
Cours de Systèmes d Exploitation

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

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

Introduction à la programmation concurrente

REALISATION d'un. ORDONNANCEUR à ECHEANCES

On appelle variable condition une var qui peut être testée et

Problèmes liés à la concurrence

Cours 2: Exclusion Mutuelle entre processus (lourds, ou légers -- threads)

Ordonnancement temps réel

J2SE Threads, 1ère partie Principe Cycle de vie Création Synchronisation

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

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

Exercices INF5171 : série #3 (Automne 2012)

Chapitre 4 : Exclusion mutuelle

4. Outils pour la synchronisation F. Boyer, Laboratoire Lig

Projet gestion d'objets dupliqués

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

1 Mesure de la performance d un système temps réel : la gigue

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

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

Info0604 Programmation multi-threadée. Cours 5. Programmation multi-threadée en Java

Synchro et Threads Java TM

SYSTÈME DE GESTION DE FICHIERS

Métriques de performance pour les algorithmes et programmes parallèles

Chapitre 1 : Introduction aux bases de données

Cours Programmation Système

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Cours de Génie Logiciel

Les transactions 1/46. I même en cas de panne logicielle ou matérielle. I Concept de transaction. I Gestion de la concurrence : les solutions

SYSTÈME DE GESTION DE FICHIERS SGF - DISQUE

C++ COURS N 2 : CLASSES, DONNÉES ET FONCTIONS MEMBRES Classes et objets en C++ Membres d'une classe Spécification d'une classe Codage du comportement

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

Gestion des transactions et accès concurrents dans les bases de données relationnelles

INITIATION AU LANGAGE JAVA

IV- Comment fonctionne un ordinateur?

PROBLEMES D'ORDONNANCEMENT AVEC RESSOURCES

Introduction aux Systèmes et aux Réseaux

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

INTRODUCTION À LA PROGRAMMATION CONCURRENTE

I. Introduction aux fonctions : les fonctions standards

Gestion des processus

CEG4566/CSI4541 Conception de systèmes temps réel

DU BINAIRE AU MICROPROCESSEUR - D ANGELIS CIRCUITS CONFIGURABLES NOTION DE PROGRAMMATION

Institut Supérieure Aux Etudes Technologiques De Nabeul. Département Informatique

ET 24 : Modèle de comportement d un système Boucles de programmation avec Labview.

Cours 1 : Qu est-ce que la programmation?

Chapitre 2. Classes et objets

DAns un système multi-utilisateurs à temps partagé, plusieurs processus

Partie 7 : Gestion de la mémoire

Informatique industrielle A Systèmes temps-réel J.F.Peyre. Partie I : Introduction

Les diagrammes de modélisation

Guide de fonctions du téléphone du système SCI Norstar

gestion des processus La gestion des processus

CARPE. Documentation Informatique S E T R A. Version Août CARPE (Documentation Informatique) 1

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

Cours d initiation à la programmation en C++ Johann Cuenin

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

Projet Active Object

1. Utilisation du logiciel Keepass

Introduction : les processus. Introduction : les threads. Plan

L exclusion mutuelle distribuée

Programmation Objet - Cours II

NFP 121. Java et les Threads. Présentation : Thierry Escalarasse Mai 2007

Fiche des fonctions du téléphone Business Communications Manager

Traduction des Langages : Le Compilateur Micro Java

C++ Programmer. en langage. 8 e édition. Avec une intro aux design patterns et une annexe sur la norme C++11. Claude Delannoy

Cours Informatique Master STEP

LOG4430 : Architecture et conception avancée

Introduction à la Programmation Parallèle: MPI

Généralités sur le Langage Java et éléments syntaxiques.

GOL-502 Industrie de services. Travaux Pratique / Devoir #7

Le langage C. Séance n 4

Analyse du temps de réponse des systèmes temps réel

Rappel. Analyse de Données Structurées - Cours 12. Un langage avec des déclaration locales. Exemple d'un programme

Cours de Base de Données Cours n.12

Initiation à la programmation en Python

Chapitre 4 : Outils de communication centralisés entre processus


LE PROBLEME DU PLUS COURT CHEMIN

Définitions. Numéro à préciser. (Durée : )

Évaluation et implémentation des langages

Conception des systèmes répartis

Premiers Pas en Programmation Objet : les Classes et les Objets

Implémentation des SGBD

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

Arithmétique binaire. Chapitre. 5.1 Notions Bit Mot

Algorithmique et Programmation, IMA

4. Groupement d objets

NIVEAU D'INTERVENTION DE LA PROGRAMMATION CONCURRENTE

ACTIVITÉ DE PROGRAMMATION

Cours A7 : Temps Réel

Un ordonnanceur stupide

Éléments d informatique Cours 3 La programmation structurée en langage C L instruction de contrôle if

Initiation à LabView : Les exemples d applications :

Introduction à la programmation orientée objet, illustrée par le langage C++ Patrick Cégielski

Ordinateurs, Structure et Applications

ORDONNANCEMENT CONJOINT DE TÂCHES ET DE MESSAGES DANS LES RÉSEAUX TEMPS RÉELS 4. QUELQUES EXEMPLES DU DYNAMISME ACTUEL DU TEMPS RÉEL

INF6500 : Structures des ordinateurs. Sylvain Martel - INF6500 1

SAGASAFE Mode d'emploi de la série DCP Version 7.0

Transcription:

CEG4566/CSI4541 Conception de systèmes temps réel Chapitre 8 - Communication et synchronisation dans les systèmes temps réel Sommaire 8.1 Objets partagés et exclusion mutuelle 8.2 Moniteurs et synchronisation 8.3 Sémaphores vs moniteurs 8.4 Les moniteurs 8.5 Conclusion générale sur la synchronisation et les moniteurs 8.6 Blocages 8.7 Communication par message 8.1 Objets partagés et exclusion mutuelle 8.1.1 Introduction Pour des raisons d efficacité (récupération des temps morts) et de lisibilité, une application en temps réel est divisée en tâches. Ces tâches vont mettre en œuvre des algorithmes portant sur un ensemble de ressources qui peuvent être privées ou être partagées. Des mécanismes de gestion d accès concurrent aux ressources doivent être définis. 8.1.2 Exemples 1. Une séquence d opérations lire/modifier/écrire sur une variable globale A. Tâche 1 Tâche 2 Lire A Lire A A=A+10 A=A+30 Écrire A Écrire A Supposons que la tâche 2 préempte la tâche 1, suite à une interruption. On pourrait aboutir au scénario suivant : Tâche 1 Tâche 2 Lire A Lire A A=A+30 Écrire A A=A+10 Écrire A Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 1

2. L UART et 2 tâches tentant de l utiliser simultanément : Tâche 1 UART Tâche 2 Test (Tx = libre?) retourne OK Test (Tx = libre? retourne OK Écriture Tx = OutChar 1 Écriture Tx = OutChar 2 Erreur = débordement Dans ces exemples, le problème vient du fait qu une séquence d opération est interrompue, d où la notion de séquence atomique. Les problèmes d atomicité concernent toutes les ressources du système; - Zone mémoire, - Registres de périphériques, - Variables ou groupe de variables, - Portions de code effectuant des accès non contrôlés par l OS à une ressource. 8.1.3 Notion d exclusion mutuelle C est une primitive de synchronisation utilisée pour éviter que des ressources partagées d'un système ne soient utilisées en même temps. Son implémentation varie selon les systèmes. Ces algorithmes permettent de réguler l'accès aux données, par exemple pour qu'une routine ne s'exécute qu'une seule fois en même temps. Un Mutex est un objet d'exclusion mutuelle (MUTual EXclusion device), et est très pratique pour protéger des données partagées de modifications concurrentes et pour implémenter des sections critiques Certains algorithmes utilisent un état pour commander l'exécution : les Mutex doivent savoir si les programmes concernés sont occupés (busy) ou s'ils ont terminé et sont en attente (wait). Un Mutex peut ête dans deux états : déverrouillé ou verrouillé (possédé par un thread). Un mutex ne peut être pris que par un seul thread à la fois. Un thread qui tente de verrouiller un mutex déjà verrouillé est suspendu jusqu'à ce que le Mutex soit déverrouillé. 8.1.4 Section Critique et exclusion mutuelle Les processus que nous allons considérer ont la forme suivante : While(1) < Section Restante > ; < Section Critique > ; L idée est d exécuter la section critique de manière indivisible c est à dire, il faut voir de quelle manière rendre atomiques les séquences d instructions qui correspondent aux sections critiques. En d autres termes, Il faut que les processus parallèles composant l application vérifient la propriété qu à tout instant, au plus l un d entre eux soit en train d exécuter une instruction de sa section critique. Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 2

Les sections critiques sont exécutées en exclusion mutuelle. Le nombre de processus, se trouvant à un moment donné dans l une de leurs sections critiques, doit être toujours inférieur ou égal à 1. Schéma général de solution : Il est évident que l accès aux différentes sections critiques doit être contrôlé de telle manière que la propriété d exclusion mutuelle, reste vérifiée à tout instant. Donc, les processus n ont plus le droit d accéder librement à leurs sections critiques. L accès aux sections critiques doit se faire selon des protocoles spécifiques. Ces protocoles se présentent sous la forme de deux sections d instructions qui vont entourer de part et d autre la section critique. Il s agit de : La section d entrée ou prologue La section de sortie ou épilogue La section d entrée (prologue) correspond à une demande d autorisation d accès. Quant à la section de sortie (épilogue) elle correspond à une signalisation de fin d utilisation. Ainsi, le comportement de processus devient : While(1) < Section Restante > ; < Section d entrée > < Section Critique > ; < Section de sortie > La section d entrée doit pouvoir bloquer tout processus demandant d accéder à sa section critique s il existe une section critique occupée par un processus donné. L exécution d une section de sortie (épilogue) pourrait permettre le déblocage d un processus en attente. Les sections sont réservées au développement de différents protocoles pour résoudre le problème de l exclusion mutuelle dans le contexte : Système monoprocesseur Système multiprocesseur à mémoire commune Les solutions doivent vérifier les propriétés suivantes : Elles doivent assurer l exclusion mutuelle, Elles doivent éviter l interblocage, Elles doivent garantir l absence de famine, Elles doivent vérifier la condition de progression : un processus en section restante (en dehors du protocole) n a pas le droit d empêcher un autre d entrer en section critique Elles ne doivent faire aucune hypothèse sur la vitesse des processus. Un grand nombre de solutions ont été proposées. On peut les classer dans 3 grandes catégories : Les solutions matérielles, Les solutions logicielles, Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 3

Les solutions basées sur les mécanismes de synchronisation de haut niveau 8.1.5 Question comment protéger l accès aux sections critiques? System non préemptif: Le programmeur a un contrôle explicite sur quand et où un changement de contexte se fait, sauf pour les ISRs. Système préemptif: Le programmeur n a aucun contrôle sur le changement de contexte. Options de protection: o Désactiver les interruptions o Verrouillage tournant (spin lock) o Mutex o Sémaphore Remarque: Ces notions seront étudiées plus bas. 8.2 Moniteurs et synchronisation 8.2.1 Introduction Règle générale : Le comportement correct d un programme concurrent dépend de la synchronisation et de la communication entre ses processus. Note : Systèmes classiques vs système en temps réel Certains des mécanismes de l interaction avec le monde extérieur utilisés dans les systèmes classiques peuvent être utilisés dans les systèmes en temps réel, d autres ne permettent pas de prendre en compte les contraintes du temps réel. Interaction avec le monde extérieur dans les systèmes classiques : a) Interaction par scrutation cyclique (mode scrutation ou programmé) Avantages? Inconvénients? b) Mode interruption (Cas d'urgence) Avantages? Inconvénients? c) Mode Accès direct mémoire (DMA) Avantages? Inconvénients? Dans les interactions précédentes, une grande partie du temps processeur est consacrée à autre chose qu à l application. C est pour mieux utiliser le processeur qu on a introduit la notion de tâche. Le traitement d un événement externe est partagé entre un événement immédiat, effectué par le gestionnaire des interruptions et un traitement différé confié à une tâche (un code séquentiel dédié à un seul traitement). Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 4

Plusieurs tâches peuvent s exécuter concurremment, ce qui permet de récupérer les temps morts. D où l importance de prendre en compte tous les aspects d ordonnancement et de synchronisation 8.2.2 La synchronisation Problèmes de synchronisation Considérons le cas de deux processus P1 et P2 suivants : P1 While (1) A1; B1; P2 While (1) A2; B2; A1, A2, B1 et B2 sont des instructions atomiques. Dans un système multiprogrammé/temps partagé, ces 2 processus peuvent s exécuter selon l un des schémas suivants : A1 ; A2 ; B1 ; B2 ; A1 ; B1 ; A2 ; B2 ; A1 ; B1 ; B2 ; A2 ; B1 ; B2 ; A1 ; A2 ; B1 ; A1 ; B2 ; A2 ; B1 ; A1 ; A2 ; B2 ;......... On parle d un entrelacement non déterministe. Pour que cette application soit valide, il faut que toutes les séquences possibles donnent le même résultat spécifié par le problème. La validité du résultat ne peut pas être garantie si ces instructions manipulaient des données communes aux deux processus. Exemple : Considérons le cas de deux processus P1 et P2 utilisant une variable commune N. N est une variable, à valeurs entières, supposée être initialisée à zéro. Les codes de P1 et de P2 contiennent chacun une instruction permettant d incrémenter la valeur de N. P1 N:=N+1;. P2 N:=N+1;. Le résultat de l application précédente (valeur finale de N) peut être 1 ou 2 en fonction de la séquence (ordre des instructions) exécutée. L instruction N = N+1 n est pas une instruction atomique. Elle peut être remplacée par le compilateur par une séquence identique à la séquence suivante : Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 5

LoadA N /*charger l accumulateur par la valeur de la case mémoire N* / ADA# 1 /*additionner 1 à la valeur de l accumulateur */ StoreA N /*stocker la valeur de l accumulateur dans la case mémoire N*/ Le problème, mentionné plus-haut (les résultats), vient précisément de la non-atomicité de cette instruction. Durant son exécution, elle peut être interrompue conduisant ainsi à l activation de l autre processus. Si une première interruption se produit après «LoadA N» et avant «ADA# 1» du premier processus faisant passer l unité centrale au deuxième processus et si une deuxième interruption se produit après le «StoreA N» du deuxième processus alors la valeur obtenue à la fin par N serait 1 au lieu de 2. Sans précautions particulières, le résultat final dépend donc de certains facteurs aléatoires (instants d occurrence des interruptions). Note : Il faut noter que cette dépendance des facteurs aléatoires n est pas acceptable (manque de déterminisme), particulièrement dans les systèmes en temps réel critiques. 8.2.2.1 Les solutions matérielles Nous pouvons distinguer dans cette catégorie plusieurs solutions. Elles s appuient toutes sur un dispositif matériel. a) Désarmement des interruptions L'idée consiste tout simplement à ne pas allouer l unité centrale à un autre processus tant que le processus courant est dans une section critique. De cette façon, nous avons la certitude que la section critique va s exécuter de manière indivisible. Avant d entrer dans une section critique, le processus masque les interruptions. Il les restaure à la fin de la section critique. Il ne peut être alors suspendu durant l exécution de la section critique. Le comportement des processus est décrit par le schéma suivant : while(1) < Section Restante > Masquer les interruptions ; < Section Critique > Démasquer les interruptions ; Problèmes : Cette solution est dangereuse, car si le processus, pour une raison ou pour une autre, ne restaure pas les interruptions à la sortie de la section critique, ce serait la fin du système. Cette solution n assure pas l exclusion mutuelle, si le système n est pas monoprocesseur car le masquage des interruptions concernera uniquement le processeur qui a demandé l interdiction. Les autres processus exécutés par un autre processeur pourront donc accéder aux objets partagés. Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 6

En revanche, cette technique est parfois utilisée par le système d exploitation pour mettre à jour des variables ou des listes partagées par ses processus (la liste des processus prêts). b) Test-And-Set Cette solution est basée sur l utilisation d une instruction permettant de lire et d écrire le contenu d un mot mémoire de manière indivisible. Cette instruction s appelle Test-And-Set (TAS). L action réalisée par cette instruction est donnée par le pseudo-code suivant : Void TAS(int *a, int *b) *a = *b; *b = 1; Un protocole, utilisant cette instruction, a été mis au point pour résoudre le problème de la section critique. La mise en œuvre de ce protocole nécessite l utilisation de : Une variable commune, partagée entre tous les processus, appelée verrou. Elle est initialisée à 0. Une variable testi, locale à chaque processus Pi. Verrou =1 si la section critique est verrouillée, 0 sinon. Le processus entrant dans la section critique verrouille son accès (positionner verrou à 1) tant qu il est à l intérieure interdisant ainsi les autres d y entrer. A sa sortie, il déverrouille l accès en remettant verrou à 0. Le comportement des processus est décrit par le schéma suivant : while(1) < Section Restante > TAS(&testi, &Verrou) While(testi ==1) TAS(&testi, &Verrou); < Section Critique > verrou = 0 ; La validité de cette solution est fondée sur le caractère indivisible de l instruction TAS. Le premier processus réussissant à exécuter (de manière indivisible) cette instruction, trouve la variable verrou à 0 et entre, par conséquent, dans sa section critique. Pendant sa présence à l intérieur de la section critique, les processus désirant accéder à la section critique trouvent verrou =1 et doivent ainsi attendre. En effet, cette variable n est pas remise à 0 qu à la sortie de la section critique. A partir de cet instant, le premier qui exécute l instruction TAS entre à son tour dans la section critique. L exclusion mutuelle est assurée mais les autres conditions ne sont pas remplies : L attente bornée n est pas garantie. Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 7

L implantation de cette instruction dans un système à plusieurs processeurs nécessite le verrouillage du bus mémoire à chaque exécution de l instruction. Problème : Cette méthode n assure pas l exclusion mutuelle : - Supposons qu un processus est suspendu juste après avoir lu la valeur du verrou qui est égal à 0. - Ensuite, un autre processus est élu. Ce dernier teste le verrou qui est toujours égal à 0, met le verrou à 1 et entre dans sa section critique. - Ce processus est suspendu avant de quitter la section critique. Le premier processus est alors réactivé, il entre dans sa section critique et met le verrou à 1. - Les deux processus sont en même temps en section critique. 8.2.2.2 Les solutions logicielles Résoudre le problème de l exclusion mutuelle n est pas une tâche facile compte tenu des contraintes à satisfaire. Afin de mesurer cette difficulté, nous allons considérer plusieurs tentatives violant chacune quelques propriétés d une bonne solution. a) Première solution (algorithme 1 : l alternance) Une autre proposition consiste à utiliser une variable tour qui mémorise le tour du processus qui doit entrer en section critique. tour est initialisée à 0. Cet algorithme considère le cas de deux processus P1 et P2. L idée est de permettre à ces deux processus dans leurs sections critiques à tour de rôle. On utilise une variable commune tour dont les seules valeurs possibles sont 1 et 2. Avant qu un processus Pi puisse entrer dans la section, il consulte la variable tour. L accès à sa section critique lui est interdit tant que ce n est pas son tour d y entrer c est à dire la valeur courante de tour est différente de son numéro i. A sa sortie de sa section critique un processus passe le tour à l autre processus en affectant à tour le numéro de l autre. Problème : Un processus peut être bloqué par un processus qui n est pas en section critique. - P1 lit la valeur de tour qui vaut 0 et entre dans sa section critique. Il est suspendu et P2 est exécuté. - P2 teste la valeur de tour qui est toujours égale à 0. Il entre donc dans une boucle en attendant que tour prenne la valeur 1. Il est suspendu et P1 est élu de nouveau. Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 8

- P1 quitte sa section critique, met tour à 1 et entame sa section non critique. Il est suspendu et P2 est exécuté. - P2 exécute rapidement sa section critique, tour = 0 et sa section non critique. Il teste tour qui vaut 0. Il attend que tour prenne la valeur 1. b) Deuxième solution (algorithme 2) Cet algorithme utilise 2 variables D1 et D2 (drapeaux) initialisées à faux correspondant aux demandes respectives de P1 et P2 d entrer en section critique. Un processus Pi désirant entrer dans la section critique commence par lever son drapeau (affecte à Di la valeur vrai), puis il consulte le drapeau de l autre processus (Dj). Il ne peut entrer que si Dj == faux c est à dire Pj ne demande pas à entrer dans sa section critique. A sa sortie Pi positionne Di à faux signalant qu il se désintéresse provisoirement de sa section critique. L algorithme devient : While (1) < section restante > Di = vrai ; While (Dj) ; < section critique > Di = faux; c) Troisième solution (algorithme 3 : Peterson) Les sections précédentes ont montré les difficultés du problème de la section critique. En effet, en plus de la réalisation mutuelle, une solution valide doit garantir : Progression Absence de blocage L attente bornée La dernière condition permet d assurer une certaine équité entre les processus. Quand un processus est en attente de sa section critique, il existe une borne supérieure au nombre de fois où d autres processus exécutent leur section critique. Il faut interdire aux processus d exécuter itérativement leur section critique en laissant un processus attendre pendant une durée arbitrairement longue l entrée dans sa propre section critique. En 1981 une solution a été proposée. Nous allons l étudier pour le cas de deux processus. Le principe de cette solution consiste à combiner les deux tentatives précédentes (algorithme 1 et algorithme 2) afin de combiner leurs avantages. Ainsi, les deux processus partagent : Une variable commune tour initialisée à 1 2 variables booléennes D1 et D2 initialisées à faux Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 9

Ces variables ont les mêmes rôles que précédemment. La variable tour permet d éviter l interblocage, et les 2 variables booléennes D1 et D2 permettent d assurer la progression. Donc, un processus Pi n aura pas le droit d entrer dans sa section critique quand l autre processus Pj a demandé à entrer dans sa section critique et en plus c est le tour de ce deuxième processus de passer. Donc, un processus Pi désirant entrer dans sa section critique, commence par lever son drapeau (affecte à Di la valeur «vrai») et cède immédiatement son tour à l autre (affecte à tour la valeur j). Puis, il tente d entrer dans sa section critique. Ce processus doit être bloqué si l autre processus, Pj, a fait déjà aussi sa demande (c est à dire Dj== Vrai) et en plus c est le tour de Pj de passer (tour == J). A sa sortie de sa section critique, le processus Pi doit tout simplement baisser son drapeau (c est à dire affecter à Di la valeur «Faux») L algorithme exécuté par le processus Pi devient : While (1) < section restante > Di = vrai ; Tour = j ; While (Dj et tour ==j ) ; < section critique i > Di = faux; Problème : Attente active = consommation du temps CPU Les solutions (logicielles et matérielles) introduites précédemment sont caractérisées par une boucle d attente active : While (condition) ; < Section critique > Ces solutions présentent l inconvénient de charger inutilement l unité centrale. L idée est de ne plus allouer l unité centrale aux processus demandant d entrer en section critique tant que cette dernière est occupée par un processus. Il existe plusieurs solutions dont : Les sémaphores Les moniteurs 8.3 Sémaphores vs moniteurs Donc, deux mécanismes classiques peuvent être utilisés pour protéger des données accédées par plusieurs tâches : Les sémaphores qui ne peuvent être pris qu un nombre déterminé de fois (si le sémaphore est déjà pris une nouvelle tentative bloquera l appelant) Les moniteurs qui permettent «d encapsuler» des données en définissant des règles d accès exclusif à ces données Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 10

8.3.1 Sémaphore et verrou Un sémaphore S est composé de : - Un compteur Sn, initialisé lors de la création du sémaphore - Une liste de tâches en attente sur ce sémaphore St, initialement vide Lorsqu une tâche T opère sur un sémaphore, les opérations sur le sémaphore sont : P(S) : prise du sémaphore (demande d'une ressource) Dans tous les cas, décrémenter Sn Si Sn < 0, ajouter T en queue de St et bloquer la tâche T P(S) est une opération potentiellement bloquante, c'est un cas de contention (plus de candidats que de ressources) V(S) : relâchement du sémaphore (libération d'une ressource) Dans tous les cas, incrémenter Sn Si St n'est pas vide, débloquer la première tâche de la liste et la retirer de la liste V(S) n'est jamais une opération bloquante Remarques: - Sn a un double rôle o lorsque Sn 0, il représente le nombre de ressources libres o lorsque Sn < 0, il représente le nombre d'entrées dans la file d'attente (Sn = St ) - Un verrou est un sémaphore initialisé avec Sn = 1 - Le sémaphore doit protéger ses propres structures contre l'accès concurrent : il utiliser une instruction test-and-set fournie par le processeur et gérée par le matériel. 8.3.2 Remarques sur l accès concurrent Une ressource peut être protégée par une ou plusieurs sections critiques utilisant un même verrou. Dans la section critique, une tâche : - peut accéder librement à la ressource - peut modifier librement la ressource - ne doit pas attendre une autre ressource La longueur des sections critiques affecte le temps de réponse du système. Réservation de ressource : Les sections critiques ne suffisent pas : - une ressource peut être bloquée pendant longtemps (réseau) - une tâche de haute priorité peut avoir besoin d'une ressource bloquée Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 11

Il y a des risques de blocage : une tâche de haute priorité peut être bloquée par une tâche de plus basse priorité. Héritage de priorité : Pour éviter les inversions de priorité, on peut utiliser l'héritage de priorité : - une tâche T1 a pris une ressource R - une tâche T2 plus prioritaire souhaite prendre la ressource R - on augmente temporairement la priorité de la tâche T1 à la priorité de la tâche T2 pour qu'elle libère plus vite la ressource R Plafonnement de priorité : Il est possible d'éviter les inversions de priorité en affectant un plafond aux ressources. Une tâche ne peut pas prendre une ressource dont le plafond (calculé a priori) est plus important que la priorité de la tâche. Si une tâche veut prendre une ressource R, elle doit attendre que le plafond de toutes les ressources bloquées soient moins important que sa propre priorité (ou égal). 8.3.3 Quelques critiques concernant les sémaphores : - Les sémaphores sont un bon moyen bas-niveau de réaliser de la synchronisation, mais leur utilisation peut comporter des erreurs. - Si un sémaphore est oublié ou mal placé, le programme peut se planter. L exclusion mutuelle peut ne pas être assurée et un blocage peut avoir lieu juste au moment où apparaît un évènement rare et critique. - Bien que les sémaphores fournissent un mécanisme pratique et efficace pour la synchronisation de processus, leur utilisation incorrecte peut toutefois conduire à des erreurs de synchronisation difficiles à détecter, puisqu'elles ne surviennent que si des séquences d'exécution particulières ont lieu et que celles-ci ne produisent pas toujours. - Une primitive de synchronisation plus élaborée et structurée peut être nécessaire. - Aucun langage concurrent de haut niveau ne dépend entièrement des sémaphores. Ils sont importants mais pas très conseillés dans le domaine du temps-réel. 8.3.4 Exemple: Problème du producteur et du consommateur - Deux processus partagent une mémoire tampon de taille fixe. L un d entre eux, le producteur, met des informations dans la mémoire tampon, et l autre, les retire. - Le producteur peut produire uniquement si le tampon n est pas plein. Le producteur doit être bloqué tant que le tampon est plein. - Le consommateur peut retirer un objet du tampon uniquement si le tampon n est pas vide. Le consommateur doit être bloqué tant que le tampon est vide. - Les deux processus ne doivent pas accéder à la fois au tampon. Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 12

- La solution du problème au moyen des sémaphores utilise trois sémaphores. - Le premier, nommé plein, compte le nombre d emplacements occupés. Il est initialisé à 0. - Le second, nommé vide, compte le nombre d emplacements libres. Il est initialisé à N (taille du tampon). - Le dernier, nommé Mutex, assure l exclusion mutuelle pour l accès au tampon (lorsqu un processus utilise le tampon, les autres ne peuvent pas y accéder). 8.4 Les moniteurs 8.4.1 Introduction - Pour traiter les insuffisances des sémaphores, on a développé des constructions langage de haut niveau. Dans ce qui suit, on décrira une construction fondamentale de haut niveau : le type moniteur. - Les moniteurs proposent une solution de "haut-niveau" pour la protection de données partagées (Hoare 1974) - Ils simplifient la mise en place de sections critiques - Ils sont définis par o des données internes (appelées aussi variables d'état) o des primitives d'accès aux moniteurs (points d'entrée) o des primitives internes (uniquement accessibles depuis l'intérieur du moniteur) o une ou plusieurs files d'attentes 8.4.2 Sémantique des moniteurs - Seul un processus (ou tâche ou thread) peut être actif à un moment donné à l'intérieur du moniteur. - La demande d'entrée dans un moniteur (ou d'exécution d'une primitive du moniteur) sera bloquante tant qu'il y aura un processus actif à l'intérieur du moniteur. L'accès à un moniteur construit donc implicitement une exclusion mutuelle - Lorsqu'un processus actif au sein d'un moniteur ne peut progresser dans son travail (une certaine condition est fausse, ou lorsqu il lui manque certaines ressources) il faut pouvoir "rendre" l'accès au moniteur et mettre «en attente» le processus actif - De même il faudra pouvoir «réveiller» un processus en attente lorsque l on modifie les variables internes du moniteur - Il existe pour cela deux types de primitives o wait : qui met en attente l'appelant et libère l'accès au moniteur o signal : qui réveille un des processus en attente à l'intérieur du moniteur (un processus qui a exécuté précédemment un wait) - Selon les langages (ou les normes) ces mécanismes peuvent être implémentés de différentes façons : Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 13

o méthodes «wait / notify / notifyall» en Java et méthodes «synchronized» o primitives «pthread_cond_wait / pthread_cond_signal» en Posix et variables conditionnelles o gardes associées aux entrées en Ada, instruction «requeue» et objets protégés - La sémantique des réveils peut varier : o Qui réveille-t-on (le plus ancien, le plus prioritaire, un choisi au hasard, ) o Quand réveille-t-on (dès la sortie du moniteur, au prochain ordonnancement, ) 8.4.3 Propriétés de moniteurs Une procédure définie à l'intérieur d'un moniteur ne peut accéder qu'aux variables qui sont déclarées localement à l'intérieur du moniteur et à tous les paramètres formels qui sont passés aux procédures. La structure du moniteur ne permet qu'à un seul processus à la fois d'être actif à l'intérieur d'un moniteur. Par conséquent, le programmeur n'a pas besoin de coder explicitement la synchronisation ; elle est bâtie dans le type moniteur. Sa structure = procédure sans paramètres A l'intérieur du moniteur, nous distinguons les différentes parties suivantes : - Déclaration des variables partagées qui ne sont pas accessibles en dehors du moniteur - Des procédures et des fonctions internes au moniteur. Elles sont les seules à manipuler des variables partagées. Leurs paramètres constituent le lien avec le programme. - Un corps comportant l'initialisation des variables. Exemple : type nombre_de_clients = Moniteur Entier N ; void incrémenter () N = N+1 ; N = 0 ; Le processus compteur admet une section critique qui consiste à incrémenter. Compteur1 et Compteur2 n'exécutent plus N= N+1; ils font appel à la procédure incrémenter du moniteur. Format de l'appel: nom_du_moniteur. nom_de_la_procedure. Tant que < le magasin_est_ouvert > faire si < entrée > alors Nombre_de_clients.incrémenter Les variables de type condition ont un rôle particulier dans les moniteurs par le biais des opérations spéciales qui sont invoquées sur elles (wait et signal). Un programmeur qui doit écrire Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 14

son schéma de synchronisation sur mesure peut définir une ou plusieurs variables de type condition. Condition x,y : L'opération: x.wait signifie que le processus invoquant cette opération est suspendu jusqu'à ce qu'un autre processus invoque x.signal. L'opération x.signal reprend l'exécution d'un processus. Si aucun processus n'est suspendu, alors l'opération signal n'a pas d'effet ; c'est à dire que l'état de x est maintenu comme si l'opération n'avait jamais été exécutée. Opposons cette opération à l'opération V sur les sémaphores qui en affecte toujours l'état. Maintenant supposons que lorsque l'opération x.signal est invoquée par un processus P, il y a un processus suspendu Q associé à la condition x. Clairement, si le processus Q suspendu est autorisé à reprendre son exécution, le processus signalant P doit attendre. Dans le cas contraire, P et Q seraient tous deux simultanément actifs à l'intérieur du moniteur. On remarque cependant que les deux processus peuvent conceptuellement poursuivre leur exécution. Il existe deux possibilités : - signal-and-wait - soit P attend que Q quitte le moniteur, soit il attend une autre condition - signal-and-continue - soit Q attend que P quitte le moniteur, soit il attend une autre condition. Il existe des arguments raisonnables pour choisir l'une ou l'autre des solutions. Puisque P s'exécute déjà dans le moniteur, signal-and-continue semble plus raisonnable. Cependant, si nous autorisons le processus P à continuer, alors la condition logique pour laquelle Q attendait peut ne plus être valable au moment où Q reprendra son exécution. signal-and-wait était défendu par Hoare, principalement du fait que l'argument précédent en sa faveur se traduisait directement en règles de preuves simples et élégantes. 8.4.4 Avantages des moniteurs - Les sections critiques sont transformées en fonctions ou procédures d'un moniteur. Elles ne sont plus dispersées. - La gestion de ces sections n'est plus à la charge de l'utilisateur. Elle est réalisée par l'implantation du moniteur. Elle garantit qu'au plus 1 processus à la fois peut accéder à cette structure. - Le moniteur tout entier est implanté comme une section critique. Note : Le problème de la section critique (Exclusion Mutuelle) est réglé. Mais, pour obtenir la puissance d'expression de sémaphores et résoudre les problèmes de synchronisation il a fallu définir et introduire un nouveau type: Condition. 8.4.5 Implantation des moniteurs (Utilisant les sémaphores) Une implantation possible, qui assure l'usage du moniteur en exclusion mutuelle, consiste à associer à chaque moniteur, un sémaphore "Ex_Mut" initialisé à 1. Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 15

Comme c'est le cas d'une section critique l'entrée dans le moniteur est précédée d'une opération Ex_Mut.P(); la sortie du moniteur est suivie de Ex_Mut.V(). La file d'attente pour l'entrée dans le moniteur est celle du sémaphore Ex_Mut. Cependant, lorsqu'on choisit de faire attendre un processus ayant exécuté une opération Signal sur une variable condition il faut définir une file d'attente supplémentaire à l'intérieur du moniteur. La file d'attente d'un autre sémaphore ("URGENT") joue ce rôle. Chaque processus après Un Signal sera placé en attente sur la file de ce sémaphore. La longueur de cette file est repérée par une variable entière : Longueur. Le compilateur remplace chaque procédure du moniteur par : Ex_Mut.P() corps de la procédure Si Longueur > 0 Alors URGENT.V(); Longueur --; Sinon Ex_Mut.V(); De cette façon, lorsqu'un processus sort du moniteur, il réveille en priorité un processus de la file du sémaphore URGENT. Si cette file est vide, il réveille un des processus en attente à l'entrée sur la file du sémaphore Ex_Mut. L'implantation des variables de type condition se fait de manière analogue à l'aide des sémaphores et des variables entières. Ces dernières représentent la longueur de la file d'attente du sémaphore. Le compilateur remplace donc chaque procédure du moniteur par : Ex_Mut.P() corps de la procédure Si Longueur > 0 Alors URGENT.V() ; Longueur -- ; Sinon Ex_Mut.V() ; Ex_Mut est un sémaphore initialisé à 1. URGENT est un sémaphore initialisé à 0. Toute variable de type condition sera implantée en utilisant un sémaphore initialisé à 0. Ainsi, Si on considère par exemple la déclaration suivante: Condition C ; L'opération C.Signal sera remplacée par le compilateur par la séquence suivante : Si! (C.Vide()) Alors Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 16

C.V() ; URGENT.P() ; Si la file de C n'est pas vide alors on en réveille un processus ; le processus appelant se bloque dans la file URGENT L'opération C.Wait sera, quant à elle, remplacé par le compilateur par la séquence suivante : Si!(URGENT.Vide()) URGENT.V() ; Sinon Ex_Mut.V() ; C.Wait ; Cette opération permet de libérer le moniteur et bloquer le processus appelant. 8.4.6 Problème de Lecteurs-Rédacteurs Bloc de données Comment utiliser un moniteur pour permettre plusieurs lectures concurrentes et une seule écriture mais pas les deux? On aura besoin d avoir un protocole d entrée et de sortie. Lecteur Lecteur Rédacteur Rédacteur Reader: start_read... stop_read Writer: start_write... stop_write Pseudo-code : type Lecteurs_Rédacteurs = Moniteur Var Booléen Ecriture ; Int Nombre_Lecteurs ; Condition Accord_Lecture, Accord_Ecriture ; Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 17

void Debut_Lecture() Si (Ecriture) Ou! (Accord_Ecriture.Vide()) Accord_Lecture.Wait ; Nombre_Lecteurs = Nombre_Lecteurs + 1 ; Accord_Lecture.Signal ; viod Fin_Lecture() Nombre_Lecteurs = Nombre_Lecteurs - 1 ; Si (Nombre_Lecteurs == 0) (Accord_Ecriture.Signal) ; void Debut_Ecriture() Si (Nombre_Lecteurs > 0) Ou (Ecriture) Accord_Ecriture.Wait ; Ecriture = Vrai ; void Fin_Ecriture() Ecriture = Faux ; Si! (Accord_Lecture.Vide()) Accord_Lecture.Signal ; Sinon Accord_Ecriture.Signal ; Ecriture = Faux ; Nombre_Lecteurs = 0 ; Lecteur...... While(1) Debut_Lecture() ; Fich.Lire(...) ; Fin_Lecture() ; Rédacteur...... While(1) Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 18

Debut_Ecriture() ; Fich.Ecrire(...) ; Fin_Ecriture() ; Remarques : La solution présentée est conforme aux règles suivantes Lorsque des lectures sont en attente de la terminaison d'une écriture, elles sont prioritaires sur la prochaine écriture. Lorsque des écritures sont en attente, une nouvelle lecture est placée en attente. 8.4.7 Conclusion sur les moniteurs - mécanisme de plus haut niveau - simplifie la mise en place de section critique - peut néanmoins conduire à des erreurs (mauvaise protection, trop de points d'entrées) 8.5 Conclusion générale sur la synchronisation et les moniteurs En modèle réparti la communication et la synchronisation entre tâches se fait par l échange de messages; on utilise principalement deux mécanismes - L appel de procédures à distance (RPC), mécanisme plutôt système - L invocation de méthodes distantes (RMI), mécanisme plutôt langage En modèle centralisé la communication et la synchronisation reposent sur le partage de données communes; il faut alors «protéger» l accès ces données à l aide de deux mécanismes : - Les sémaphores, plutôt système - Les moniteurs, plutôt langage Chapitre VIII - CEG4566/CSI4541 RNM SIGE UOttawa Hiver 2013 19