Moniteurs, Java, Threads et Processus



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

Introduction à la programmation concurrente

Problèmes liés à la concurrence

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

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

Synchro et Threads Java TM

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

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

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

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars

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

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

Cours de Systèmes d Exploitation

Threads. Threads. USTL routier 1

INITIATION AU LANGAGE JAVA

Introduction : les processus. Introduction : les threads. Plan

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

LOG4430 : Architecture et conception avancée

Programmer en JAVA. par Tama

Langage et Concepts de ProgrammationOrientée-Objet 1 / 40

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

Un ordonnanceur stupide

TP1 : Initiation à Java et Eclipse

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

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

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

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

Apprendre la Programmation Orientée Objet avec le langage Java (avec exercices pratiques et corrigés)

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

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

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

Génie Logiciel avec Ada. 4 février 2013

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

Java Licence Professionnelle CISII,

Premiers Pas en Programmation Objet : les Classes et les Objets

Cours 1: Java et les objets

Traduction des Langages : Le Compilateur Micro Java

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

as Architecture des Systèmes d Information

Projet gestion d'objets dupliqués

INTRODUCTION À LA PROGRAMMATION CONCURRENTE

Notion de thread (1/2)

Arbres binaires de recherche

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

Corrigés des premiers exercices sur les classes

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

La technologie Java Card TM

Introduction à la Programmation Parallèle: MPI

Centre CPGE TSI - Safi 2010/2011. Algorithmique et programmation :

Structure d un programme et Compilation Notions de classe et d objet Syntaxe

Quelques patterns pour la persistance des objets avec DAO DAO. Principe de base. Utilité des DTOs. Le modèle de conception DTO (Data Transfer Object)

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

Introduction aux systèmes temps réel. Iulian Ober IRIT

LMI 2. Programmation Orientée Objet POO - Cours 9. Said Jabbour. jabbour@cril.univ-artois.fr

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

TD/TP PAC - Programmation n 3

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

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

Programmation en Java IUT GEII (MC-II1) 1

Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004. Loc Jeudi 29/4/2004

Chapitre VI- La validation de la composition.

RAPPELS SUR LES METHODES HERITEES DE LA CLASSE RACINE Object ET LEUR SPECIALISATION (i.e. REDEFINITION)

Auto-évaluation Programmation en Java

Programmation MacOSX / ios

Lambda! Rémi Forax Univ Paris-Est Marne-la-Vallée

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

Langage et Concepts de Programmation Objet. 1 Attributs et Méthodes d instance ou de classe. Travaux Dirigés no2

Java Licence Professionnelle Cours 7 : Classes et méthodes abstraites

Java c est quoi? Java pourquoi?

Cette application développée en C# va récupérer un certain nombre d informations en ligne fournies par la ville de Paris :

Argument-fetching dataflow machine de G.R. Gao et J.B. Dennis (McGill, 1988) = machine dataflow sans flux de données

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

Cours 1 : La compilation

TP : Gestion d une image au format PGM

Programmation avec des objets : Cours 7. Menu du jour

Encapsulation. L'encapsulation consiste à rendre les membres d'un objet plus ou moins visibles pour les autres objets.

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Programmation d Applications Concurrentes et Distribuées (INF431)

2. Comprendre les définitions de classes

Java Licence Professionnelle CISII, Cours 2 : Classes et Objets

Langage Java. Classe de première SI

Table des matières PRESENTATION DU LANGAGE DS2 ET DE SES APPLICATIONS. Introduction

Les structures de données. Rajae El Ouazzani

Développement Logiciel

Cours 1 : Qu est-ce que la programmation?

ACTIVITÉ DE PROGRAMMATION

Noyau de concurrence par moniteur pour Java ou C# pour une autre sémantique plus fiable et plus performante

Programmation Orientée Objet Java

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

Tp 1 correction. Structures de données (IF2)

Une introduction à la technologie EJB (2/3)

Une introduction à Java

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

Les structures. Chapitre 3

Java Licence Professionnelle CISII,

Plan. Exemple: Application bancaire. Introduction. OCL Object Constraint Language Le langage de contraintes d'uml

Apprendre Java en 154 minutes

Bases de programmation. Cours 5. Structurer les données

TD/TP PAC - Programmation n 3

Gestion distribuée (par sockets) de banque en Java

Transcription:

Moniteurs, Java, Threads et Processus 1

Une vue orientée-objet de la mémoire partagée On peut voir un sémaphore comme un objet partagé accessible par deux méthodes : wait et signal. L idée du concept de moniteur est de généraliser cela à des objets et méthodes quelconques. Si plusieurs processus peuvent exécuter des méthodes sur un même objet, le problème de gérer l interaction entre ces processus se pose : Il faut assurer une certaine atomicité garantissant l exécution correcte des opérations ; Un mécanisme permettant la mise en attente de processus par rapport à une condition sur l état de l objet partagé est nécessaire. 2

Moniteurs : concept Un moniteur est une classe utilisée dans un contexte de parallélisme. Les instances de la classe seront donc des objets utilisés simultanément par plusieurs processus. Définir un moniteur se fait en définissant la classe correspondante. Nous utiliserons une syntaxe inspirée de Java. 3

Un exemple de classe : stack public class Stack { protected static int max = 300; private int nbelements; private Object[] contenu; public Stack() { nbelements = 0; contenu = new Object[max]; public void push(object e) { if (nbelements < max) contenu[nbelements++] = e; public Object pop() { if (nbelements > 0) return contenu[--nbelements]; else return null; 4

Moniteurs : première règle de synchronisation Même pour une classe aussi simple que Stack, l exécution simultanée par des processus différents de méthodes de la classe peut poser problème. Une première règle de synchronisation imposée dans le cadre des moniteurs est donc la suivante : Les méthodes d un moniteur sont exécutées en exclusion mutuelle. Note Java. En Java, l exclusion mutuelle des méthodes doit se spécifier de façon explicite à l aide de l attribut synchronized. 5

Le problème du producteur et consommateur dans le cadre des moniteurs Ce problème se résout naturellement à l aide de la classe suivante. public class PCbuffer { private Object buffer[]; /* Mémoire partagée */ private int N; /* Capacité de la zone */ private int count, in, out; /* nb d éléments, pointeurs */ public PCbuffer(int argsize) { /* création d un tampon de taille argsize */ N = argsize; buffer = new Object[N]; count = 0; in = 0; out = 0; 6

public synchronized void append(object data) { buffer[in] = data; in = (in + 1) % N; count++; public synchronized Object take() { Object data; data = buffer[out]; out = (out + 1) % N; count--; return data; Il manque évidemment la synchronisation nécessaire lorsque la zone tampon est pleine ou vide. 7

Moniteurs : la synchronisation par files d attente Pour permettre la mise en attente de processus lorsqu ils ne peuvent exécuter l opération souhaitée, on utilise des files d attente. Ces files d attente sont gérées par trois opérations. qwait() : met le processus exécutant cette opération en attente dans la file. qsignal() : débloque le premier processus en attente dans la file (sans effet si la file est vide). qnonempty() : teste que la file n est pas vide. Lorsqu un processus est mis en attente par une opération qwait(), il libère l exclusion mutuelle liée à l exécution d une méthode du moniteur. 8

Les files d attente vues comme une classe Les files d attente seront vues comme des objets instanciés à partir de la classe suivante dont la concrétisation sera donnée par la suite. public class Waitqueue {... /* données à préciser */ public Waitqueue() {... /* constructeur à préciser */ public void qwait() {... /* opération de mise en attente */ public void qsignal() {... /* opération d activation */ public boolean qnonempty() {... /* test de l état non vide de la file */ 9

Le problème du producteur et consommateur avec files d attente Pour synchroniser les producteurs et consommateurs, on utilise deux files d attente : une pour les processus en attente d un élément à consommer, une pour les processus en attente d une place dans le tampon. public class PCbuffer { private Object buffer[]; /* Mémoire partagée */ private int N ; /* Capacité de la zone */ private int count, in, out; /* nb d éléments, pointeurs */ private Waitqueue notfull, notempty; /* files d attente */ public PCbuffer(int argsize) { N = argsize; /* création d un tampon de taille buffer = new Object[N]; argsize */ count = 0; in = 0; out = 0; notfull = new Waitqueue(); notempty = new Waitqueue(); 10

public synchronized void append(object data) { if (count == N) notfull.qwait(); buffer[in] = data; in = (in + 1) % N; count++; notempty.qsignal(); public synchronized Object take() { Object data; if (count == O) notempty.qwait(); data = buffer[out]; out = (out + 1) % N; count--; notfull.qsignal(); return data; L opération qsignal n a pas d effet si la file est vide et donc cette solution ne souffre pas du problème de double signalisation rencontré dans le cadre de l utilisation des sémaphores binaires. 11

Les priorités lors d une opération qsignal Lorsque l on exécute une opération qsignal, le processus en tête de la file d attente est débloqué, mais a priori cela ne signifie pas qu il poursuit son exécution. Cela pose potentiellement un problème, car la situation qui a provoqué le qsignal (par exemple zone tampon non vide) pourrait ne plus être vraie lorsque le processus débloqué reprend effectivement son exécution (par exemple, parce qu un autre processus a pris le seul élément restant dans une zone non vide). 12

Pour éviter cela, on impose la règle suivante sur la synchronisation des moniteurs : Reprise immédiate : Le processus débloqué lors d une opération qsignal a priorité sur tout autre processus tentant d exécuter une opération sur l objet auquel la file d attente est attachée. Qu en est-il du processus exécutant l opération qsignal? Le processus exécutant l opération qsignal a priorité pour terminer la méthode en cours d exécution, lorsque le processus débloqué a terminé son opération sur le moniteur. 13

Les sémaphores vus comme moniteurs Avec le mécanisme de file d attente, les sémaphores peuvent être facilement implémentés comme des moniteurs. Cela permet aussi de prévoir d autres opérations sur un sémaphore, en particulier le test du nombre de processus en attente sur le sémaphore, ce qui nous sera utile par la suite. public class Semaphore { int value; /* la valeur du sémaphore */ int nbwait = 0; /* le nombre de processus en attente */ Waitqueue queue; public Semaphore(int inival) { value = inival; queue = new Waitqueue(); 14

public synchronized void semwait() { if (value <= 0) { nbwait++; queue.qwait(); nbwait--; value--; public synchronized void semsignal() { value++; queue.qsignal(); public synchronized int semnbwait() { return nbwait; Remarquer la nécessité de la reprise immédiate pour que cette implémentation soit correcte. 15

L implémentation des files d attente Il est clair que l implémentation des files d attente nécessite un mécanisme de base de mise en attente des processus qui doit être fourni au niveau de l environnement d exécution du programme. Nous allons temporairement ignorer ce problème en supposant que nous disposons de sémaphores implémentés directement, sans utiliser les files comme présenté ci-dessus. La reprise immédiate pose un problème, puisqu elle crée un lien entre la gestion des files et l accès en exclusion mutuelle aux méthodes du moniteur. Nous examinerons d abord une première implémentation, sans reprise immédiate, avant d introduire cette contrainte dans un deuxième temps. 16

Une implémentation des files sans reprise immédiate Une file est simplement implémentée à l aide d un sémaphore (supposé FIFO) dont la valeur est toujours 0. public class Waitqueue { private int qcount = 0; /* le nombre de processus en attente */ private Semaphore Qsem; public Waitqueue() { Qsem = new Semaphore(0); /* création du sémaphore initialisé à 0 */ public void synchronized qwait() /* opération de mise en attente */ { qcount++; Qsem.semWait(); qcount--; 17

public void synchronized qsignal() /* opération d activation */ { if (qcount > 0) Qsem.semSignal(); public boolean synchronized qnonempty() { return qcount == 0; /* test de l état non vide de la file */ Indépendamment du problème de la reprise immédiate, cette solution souffre d un risque de deadlock lié à une multiplication des verrouillages par synchronized. 18

Note Java : synchronized et les verrous Une méthode déclarée synchronized est exécutée en exclusion mutuelle par rapport aux autres méthodes relatives au même objet. Cela peut se comprendre en disant qu il y a un verrou (qui pourrait par exemple être implémenté par un sémaphore) lié à l objet. Quand une méthode synchronized appelle une méthode synchronized d un autre objet, un deuxième verrouillage sur ce nouvel objet est donc effectué. Le problème arrive quand un processus est mis en attente. Dans ce cas, il faut libérer le verrouillage, mais cela est difficile à réaliser s il y a eu une série d opérations de verrouillage. En Java, l opération élémentaire de mise en attente (voir plus loin) ne libère que le verrou de l objet courant. 19

Une implémentation des files avec reprise immédiate Pour résoudre à la fois le problème de la reprise immédiate et le problème du verrouillage multiple, nous allons gérer explicitement l exclusion mutuelle entre méthodes d un moniteur à l aide d un sémaphore. Quand un processus sera mis an attente, l opération qwait libérera explicitement l exclusion mutuelle associée à la méthode appelant l opération qwait. Pour ce faire, un argument indiquant le sémaphore d exclusion mutuelle à libérer sera donné à qwait (ainsi qu à qsignal pour pouvoir gérer la reprise immédiate). 20

Une implémentation des files avec reprise immédiate (suite) public class Waitqueue { private int qcount = 0; /* le nombre de processus en attente */ private Semaphore Qsem; public Waitqueue() { Qsem = new Semaphore(0); /* création du sémaphore initialisé à 0 */ public void qwait(semaphore Mutsem) /* opération de mise en attente */ { qcount++; Mutsem.semSignal(); Qsem.semWait(); qcount--; 21

public void qsignal(semaphore Mutsem) /* opération d activation */ { if (qcount > 0) { Qsem.semSignal(); Mutsem.semWait(); public boolean qnonempty() { return qcount == 0; /* test de l état non vide de la file */ Pour éviter les blocages, l exclusion mutuelle n est pas imposée sur les méthodes de manipulation de files d attente. Les interférences non désirées son toutefois exclues, vu qu une file est utilisée par un seul objet partagé et que les méthodes de cet objet sont déjà exécutées en exclusion mutuelle. 22

La zone tampon utilisant l implémentation des files par sémaphores public class PCbuffer { private Object buffer[]; /* Mémoire partagée */ private int N ; /* Capacité de la zone */ private int count, in, out; /* nb d éléments, pointeurs */ private Waitqueue notfull, notempty; /* files d attente */ private mutex Semaphore; /* sémaphore d exclusion mutuelle */ public PCbuffer(int argsize) { N = argsize; buffer = new Object[N]; count = 0; in = 0; out = 0; notfull = new Waitqueue(); notempty = new Waitqueue(); mutex = new Semaphore(1); 23

public void append(object data) { mutex.semwait() if (count == N) notfull.qwait(mutex); buffer[in] = data; in = (in + 1) % N; count++; notempty.qsignal(mutex); mutex.semsignal(); public Object take() { Object data; mutex.semwait() if (count == O) notempty.qwait(mutex); data = buffer[out]; out = (out + 1) % N; count--; notfull.qsignal(mutex); mutex.semsignal(); return data; 24

L urgence des processus ayant exécuté une opération qsignal Dans l implémentation précédente, la priorité n a pas été donnée aux processus ayant effectué une opération qsignal. Pour ce faire, un deuxième sémaphore d exlusion mutuelle urgent sera utilisé. L opération qwait sera appelée avec le sémaphore d exclusion mutuelle ou le sémaphore urgent suivant qu il y a ou non des processus en attente sur ce dernier. Pour ce faire on comptera explicitement le nombre de processus en attente sur urgent. En effet, un appel à semnbwait(urgent) ne compte pas les processus qui ont exécuté une opération qsignal, vont se mettre en attente sur urgent, mais ne l ont pas encore fait. En fin de méthode, on exécute une opération semsignal sur urgent s il y a un processus en attente sur ce sémaphore ; si non, on exécute l opération sur le sémaphore d exclusion mutuelle. 25

Une implémentation des files avec reprise immédiate et priorité aux processus signalant) public class PCbuffer { private Object buffer[]; /* Mémoire partagée */ private int N ; /* Capacité de la zone */ private int count, in, out; /* nb d éléments, pointeurs */ private Waitqueue notfull, notempty; /* files d attente */ private Semaphore mutex, urgent; /* sémaphores */ private int urcount; /* nb de processus en attente sur urgent */ public PCbuffer(int argsize) { N = argsize; buffer = new Object[N]; count = 0; in = 0; out = 0; urcount = 0; notfull = new Waitqueue(); notempty = new Waitqueue(); mutex = new Semaphore(1); urgent = new Semaphore(0); 26

public void append(object data) { mutex.semwait() if (count == N) { if (urcount > 0) notfull.qwait(urgent); else notfull.qwait(mutex); buffer[in] = data; in = (in + 1) % N; count++; urcount++; notempty.qsignal(urgent); urcount--; if (urcount > 0) urgent.semsignal(); else mutex.semsignal(); 27

public Object take() { Object data; mutex.semwait() if (count == 0) { if (urcount > 0) notempty.qwait(urgent); else notempty.qwait(mutex); data = buffer[out]; out = (out + 1) % N; count--; urcount++; nofull.qsignal(urgent); urcount--; if (urcount > 0) urgent.semsignal(); else mutex.semsignal(); return data; 28

Note Java : l implémentation des sémaphores Pour éviter la circularité dans l implémentation des moniteurs, il faut une implémentation des sémaphores qui ne fasse pas appel aux files d attente définies. Java fournit les primitives permettant de réaliser une telle implémentation. D une part, le caractère synchronized d une méthode en garantit l exécution en exclusion mutuelle. D autre part, Java permet la mise en attente de processus grâce aux méthodes wait(), notify() et notifyall(). 29

Note Java : wait et notify wait() : Suspend le processus courant et libère l exclusion mutuelle relative à l objet courant. notify() : Sélectionne un processus en attente sur l objet courant et le rend exécutable. Le processus sélectionné doit réacquérir l exclusion mutuelle associée à l objet (il n y a pas de reprise immédiate). notifyall() : Similaire à notify(), mais rend exécutable tous les processus en attente sur l objet courant. 30

Une première implémentation des sémaphores en Java public class Semaphore { private int value; /* la valeur du sémaphore */ private int nbwait = 0; /* nb en attente */ public Semaphore(int inival) { value = inival; public synchronized void semwait() { while (value <= 0) { nbwait++; wait(); value--; Vu l absence de reprise immédiate, la valeur du sémaphore doit être testée à nouveau lorsque l on sort du wait(). 31

public synchronized void semsignal() { value++; if (nbwait > 0) { nbwait--; notify(); public synchronized int semnbwait() { return nbwait; L opération nbwait-- se fait dans semsignal() juste avant le notify() car, étant donné l absence de reprise immédiate, effectuer cette opération dans semwait() après le wait() pourrait mener au renvoi d une valeur incorrecte par semnbwait(). La sémantique de wait() et notify() implique que cette implémentation n est pas équitable. 32

Une implémentation équitable des sémaphores en Java Pour obtenir une implémentation équitable, il faut explicitement implémenter une file d attente. La file d attente sera une file d objets sur chacun desquels exactement un processus sera mis en attente. L absence d équité lors de l exécution d une opération notify() ne posera alors plus de problème. 33

Une implémentation équitable des sémaphores en Java (suite) La classe Queue implémente une file d attente classique. public class SemaphoreFIFO { private int value; /* la valeur du sémaphore */ private int nbwait = 0; /* nb en attente */ private Queue thequeue; /* la file d attente explicite */ public SemaphoreFIFO(int inival) { value = inival; thequeue = new Queue(); 34

public void semwait() { Semaphore semelem; synchronized(this){ if (value == 0) { semelem = new Semaphore(0); thequeue.enqueue(semelem); nbwait++; else { semelem = new Semaphore(1); value--; /* synchronized */ semelem.semwait(); On sort l opération semelem.semwait() de l exclusion mutuelle pour éviter un double verrouillage. Remarquer l initialisation différente de semelem suivant que value ait la valeur 0 ou non. 35

public synchronized void semsignal() { Semaphore semelem; if (!thequeue.empty()){ semelem = thequeue.dequeue(); nbwait--; semelem.semsignal(); else value++; public synchronized int semnbwait() { return nbwait; L opération semsignal() débloque le processus bloqué sur le premier élément de la file, s il y en a un. Si non, la valeur de value est incrémentée. 36

Processus et Threads Dans le langage Java on parle de Threads et non de processus. Quelle est la différence. Un thread correspond à une exécution ayant son propre flux de contrôle ( thread peut se traduire par fil ). On peut implémenter les threads à l aide de processus, mais cela présente quelques inconvénients. Les processus opèrent dans des espaces virtuels distincts. Le partage d objets entre threads est donc relativement complexe à organiser. Vu la séparation forte entre le contexte des processus, le passage d un processus à un autre est une opération relativement lourde et donc lente. 37

Processus et Threads (suite) Plusieurs systèmes modernes ont une notion de thread ou processus léger. Ces processus se distinguent des processus traditionnels étant conçus pour coopérer (en partageant par exemple un espace virtuel) plutôt que pour travailler dans des contextes totalement distincts. Les threads système sont apparus comme outil d exploitation des machines parallèles. Les threads Java peuvent être implémentés par des threads systèmes. On peut aussi implémenter les threads Java à l intérieur d un processus système en incorporant dans le code exécuté un gestionnaire de tâches simple. 38