Un ordonnanceur stupide



Documents pareils
Synchro et Threads Java TM

Threads. Threads. USTL routier 1

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

Introduction : les processus. Introduction : les threads. Plan

Notion de thread (1/2)

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

Une introduction à la technologie EJB (2/3)

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

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars

Programmer en JAVA. par Tama

Cours de Systèmes d Exploitation

Premiers Pas en Programmation Objet : les Classes et les Objets

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

Auto-évaluation Programmation en Java

Programmation avec des objets : Cours 7. Menu du jour

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

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

INITIATION AU LANGAGE JAVA

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

Utilisation d objets : String et ArrayList

Développement Logiciel

La JVM. La machine virtuelle Java. La JVM. La JVM

Introduction à la programmation concurrente

Projet de programmation (IK3) : TP n 1 Correction

Corrigé des exercices sur les références

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

Plan du cours. Historique du langage Nouveautés de Java 7

Java Licence Professionnelle CISII,

Problèmes liés à la concurrence

JADE : Java Agent DEvelopment framework. Laboratoire IBISC & Départ. GEII Université & IUT d Evry nadia.abchiche@ibisc.univ-evry.

Package Java.util Classe générique

PIGOURIER Vincent ANNEE SPECIALE 99/00 RAPPORT DE PROJET : LES THREADS JAVA. Responsable : Serge Rouveyrol

SHERLOCK 7. Version du 01/09/09 JAVASCRIPT 1.5

TD2 Programmation concurrentielle

Support de cours Java

as Architecture des Systèmes d Information

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

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

Chapitre 10. Les interfaces Comparable et Comparator 1

Corrigés des premiers exercices sur les classes

Remote Method Invocation Les classes implémentant Serializable

Pour plus de détails concernant le protocole TCP conférez vous à la présentation des protocoles Internet enseignée pendant.

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

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

Objets et Programmation. origine des langages orientés-objet

Une introduction à Java

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

Communication inter-processus (IPC) : tubes & sockets. exemples en C et en Java. F. Butelle

Programmation Par Objets

Calcul Parallèle. Cours 5 - JAVA RMI

Programmation Orientée Objet - Licence TIS CM8/9. Rappel sur la séance précédente. Lancelot Pecquet Lancelot.Pecquet@math.univ-poitiers.

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

Programmation Réseau. Sécurité Java. UFR Informatique jeudi 4 avril 13

2. Comprendre les définitions de classes

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

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

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

Programmation Objet Java Correction

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

Conventions d écriture et outils de mise au point

SugarCubes. Jean-Ferdinand Susini Maître de Conférences, CNAM Chaire systèmes enfouis et embarqués. Paris, le 9 janvier, 2009

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

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

Programmation par les Objets en Java

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

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

Programme Compte bancaire (code)

Développement mobile MIDP 2.0 Mobile 3D Graphics API (M3G) JSR 184. Frédéric BERTIN

Serveur d'application Client HTML/JS. Apache Thrift Bootcamp

La gestion des exceptions

TP1 : Initiation à Java et Eclipse

Introduction au langage Java

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

Programmation d Applications Concurrentes et Distribuées (INF431)

INF 321 : mémento de la syntaxe de Java

Cours 1: Java et les objets

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

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

Cours Programmation Système

Sommaire Introduction... 3 Le but du projet... 3 Les moyens utilisés... 3 Informations sur le client FTP... 4 Pourquoi une version Linux et

RMI le langage Java XII-1 JMF

TD Objets distribués n 3 : Windows XP et Visual Studio.NET. Introduction à.net Remoting

RMI. Remote Method Invocation: permet d'invoquer des méthodes d'objets distants.

Desktop Intégration. Rémi Forax

Java Licence Professionnelle CISII, Cours 2 : Classes et Objets

TD/TP PAC - Programmation n 3

TD/TP PAC - Programmation n 3

Dis papa, c est quoi un bus logiciel réparti?

IFT287 Exploitation de base de données relationnelles et orientées objet. Laboratoire Mon premier programme Java en Eclipse

Certificat Big Data - Master MAthématiques

Environnements de développement (intégrés)

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

Page 1 sur 5 TP3. Thèmes du TP : l la classe Object. l Vector<T> l tutorial Interfaces. l Stack<T>

TP, première séquence d exercices.

Java DataBaseConnectivity

Bases de données et fournisseurs de contenu

Modèle à composants. Daniel Hagimont. IRIT/ENSEEIHT 2 rue Charles Camichel - BP TOULOUSE CEDEX 7. Remerciements

Apprendre Java en 154 minutes

ACTIVITÉ DE PROGRAMMATION

PROGRAMMATION PAR OBJETS

Transcription:

Un ordonnanceur simple Université Paris Sud L objet des exercices qui suivent est de créer un ordonanceur implantant l algorithme du tourniquet ( round-robin scheduler ). La technique utilisée pour élire une activité (une activité élue est exécutée par la CPU) est la modification des priorités. Exercice 1 Un ordonnanceur stupide Créer un programme Java qui provoque un réordonancement périodique des activités (threads) java. Pour cela, créer une classe SimpleScheduler héritant de Thread qui fixe (dans son constructeur) sa priorité au maximum possible ; ensuite, elle passe son temps (en boucle) à dormir un certain quantum de temps (ce quantum étant un champ de la classe). À chaque mise en sommeil de l activité de type SimpleScheduler, la machine virtuelle Java sélectionne la prochaine activité qui doit tourner. Un réordonancement est donc provoqué tous les quantum de temps. Tester cet ordonnanceur à l aide d une classe TestThread, héritant de Thread et comportant comme champ une chaîne de caractère identificatrice de l activité. La méthode run() doit afficher cette chaîne identificatrice de l activité. Note : le code solution de cet exercice est extrêmement court et simple. Exercice 2 Un ordonnanceur en tourniquet simple Créer un ordonnanceur un peu plus réaliste implantant la méthode du tourniquet avec priorités. Plus précisément, on établit 3 niveaux de priorités pour les activités : Niveau NORM_PRIORITY+1 (en général égal à 6). L ordonanceur est une activité tournant au niveau de priorité NORM_PRIORITY+1. Cela lui permet de tourner préférentiellement aux activités standard créées par la machine virtuelle java (de priorité NORM_PRIORITY). Cette activité passe le plus clair de son temps à dormir (via un sleep()), elle n est donc pas usuellement l activité en train de s exécuter. Niveau NORM_PRIORITY-1 (en général égal à 4). L ordonnanceur sélectionne une activité parmi toutes celles qu il contrôle et lui assigne la priorité NORM_PRIORITY-1. Très souvent, elle sera l activité non bloquée (ou en sommeil) de plus haute priorité et deviendra donc l activité en train de s exécuter. 1

2 Un ordonnanceur simple Niveau MIN_PRIORITY+1 (en général égal à 2). Toutes les autres activités sous contrôle de l ordonnanceur sont à une priorité de niveau MIN_PRIORITY+1. Pluisqu il y a toujours une activité de niveau de priorité NORM_PRIORITY-1 (> MIN_PRIORITY+1), ces activités ne tournent en fait jamais à ce niveau de priorité. Elles restent à cette priorité jusqu à ce que l une d entre elles soit élue par l ordonnanceur qui lui monte sa priorité à NORM_PRIORITY-1, auquel cas elle devient l activité en cours d exécution. L idée est que le programmeur assigne certaines activités à être sous le contrôle de l ordonnanceur. L ordonnanceur sélectionne une et une seule de ces activités et lui monte sa priorité à NORM_PRIORITY-1 (en général égal à 4), alors que le reste des activités ont une priorité de MIN_PRIORITY+1 (en général égal à 2). L activité de priorité NORM_PRIORITY-1 devient l activité en cours d exécution ; de temps en temps, l ordonnanceur se réveille et sélectionne une nouvelle activité comme unique activité de priorité NORM_PRIORITY-1. Afin de garder une trace de toutes les activités, on utilisera une liste circulaire, la classe CircularList dont le code est fourni en fin de feuille d exercices. Cette classe permet d ajouter des classes à la liste avec la méthode insert() et d en enlever avec la méthode delete(). On peut passer d un élément à un autre de la liste par getnext(). Voici quelques spécifications plus précises. La classe ordonnanceur créée, par exemple RoundRobinScheduler, qui hérite de la classe Thread. On crééra trois champs : le quantum de temps, la liste (de type CircularList) des activités gérées par l ordonnanceur et l activité en cours d exécution. Outre le constructeur et la méthode run(), on crééra trois méthodes. C est à l aide de ces trois méthodes qu un utilisateur va interagir avec l ordonnanceur. La première méthode, void addthread(thread th), publique (public), réalise l ajout d une activité à la liste de celles déja gérées et met à jour la priorité de cette dernière. La deuxième méthode, publique (public), void removethread(thread th) réalise la suppression d une activité de cette liste. La troisième méthode void displaythreadqueue(), privée (private), affiche les activités mises en jeu ici, par priorité. Plus précisément, elle affiche les activités de priorité MIN_PRIORITY+1 (2) et l activité de priorité NORM_PRIORITY-1 (4). Cette méthode est appelée au sein de run() de la classe RoundRobinScheduler. Supposons par exemple avoir 4 activités th1, th2, th3 et l activité ordonnanceur de type RoundRobinScheduler que nous nommerons scheduler par la suite. Au début de l exécution de l ordonnanceur, les activités sont dans les états suivants : PRIORITE 2 : PRIORITE 6 : th1 -> th2 -> th3 -> null scheduler -> null Étant l activité de plus haute priorité, scheduler est l activité en cours d exécution. L une des premières choses qu elle fait est de mettre la priorité de th1 à 4 (c est-à-dire NORM_PRIORITY-1) : PRIORITE 2 : PRIORITE 4 : PRIORITE 6 : th2 -> th3 -> null th1 -> null scheduler -> null Ensuite, scheduler se met en sommeil pendant un quantum de temps, ce qui la met dans l état bloqué. Ceci permet à th1 de devenir l activité élue, c.à.d. en cours d exécution :

Exercice 2 Un ordonnanceur en tourniquet simple 3 PRIORITE 2 : th2 -> th3 -> null PRIORITE 4 : th1 -> null BLOQUEE : scheduler -> null Lorsque scheduler se réveille, elle remet la priorité de th1 à 2 (MIN_PRIORITY+1) et fixe la priorité de th2 à 4 (NORM_PRIORITY-1) : PRIORITE 2 : PRIORITE 4 : PRIORITE 6 : th3 -> th1 -> null th2 -> null scheduler -> null Et le cycle continue. Un code de test possible de cette classe d ordonnanceur est le suivant : /* * Classe de test de BasicRoundRobinScheduler */ class BasicTestThread extends Thread { String id; public BasicTestThread(String s) { id = s; public void docalc(int i) { boolean dummy = true; for (int k = 0; k < 1000; k++) for (int l = 0; l < 10000; l++) { if (dummy == true ) dummy = false; else dummy = true; public void run() { int i; for (i = 0; i < 10; i++) { docalc(i); public class BasicTest { public static void main(string args[]) { BasicRoundRobinScheduler c = new BasicRoundRobinScheduler(200, true); BasicTestThread t1, t2, t3; t1 = new BasicTestThread("Thread 1 en cours"); t2 = new BasicTestThread("Thread 2 en cours"); t3 = new BasicTestThread("Thread 3 en cours"); c.addthread(t1, "th1"); c.addthread(t2, "th2"); c.addthread(t3, "th3");

4 Un ordonnanceur simple t1.start(); t2.start(); t3.start(); c.start(); try { t1.join(); t2.join(); t3.join(); c.displaythreadqueue(); c.join(); catch (InterruptedException e) { System.out.println(" Activites interrompues "); System.out.println("Activites terminees. "); Exercice 3 Un ordonanceur fonctionnel Cet excercice, comme le suivant, est une amélioration de l ordonnanceur réalisé en exercice Exercice 2. 1) Accès en exclusion mutuelle à l activité courante. Supposons que l ordonnanceur vienne de choisir une nouvelle activité, th, dont il monte la priorité à 4 (NORM_PRIORITY-1) et qu il se mette en sommeil. Pendant son sommeil, le programme qui utilise l ordonnanceur (l utilisateur) appelle removethread() pour enlever l activité th. Lors du réveil de l ordonnanceur, ce dernier cherche à remettre l activité th en priorité 2 (MIN_PRIORITY+1) et échoue. Il faut donc un moyen pour removethread() d avertir l ordonnanceur que l activité en cours d exécution a été enlevée. Pour ce faire, créer une variable d instance privée (private) de type Thread et nommée par exemple current (remplaçant certainement une variable locale à la méthode run()), qui est mise à null par removethread() et qui est testée par run() avant que l ordonnanceur ne remette la priorité de th à 2 (MIN_PRIORITY+1). Rendre l accès à cette variable exclusif au moyen de blocs synchronisés placés dans les méthodes removethread() et run(). 2) Terminaison d activités. Nous allons ici chercher à nous prémunir contre les activités qui se terminent lorsqu elles sont sous le contrôle de l ordonnanceur. En particulier, la méthode run() modifie la priorité d une activité, ce qui n est une opération valide que si l activité est dans l état en cours d exécution. Que se passe-t-il si l activité que l ordonnanceur a mise en priorité 4 (NORM_PRIORITY-1) sort de sa méthode run() alors que l ordonnanceur est en train de dormir? Lorsque l ordonnanceur se réveille, il essaie de fixer la priorité de cette activité, qui est maintenant dans l état morte, à 2 (MIN_PRIORITY+1), ce qui génère une exception. De manière similaire, si l activité en cours d exécution décide d appeler la méthode stop() de l une des activités en priorité 2 (MIN_PRIORITY+1), la prochaine fois que l ordonnanceur veut sélectionner cette activité et modifier sa priorité, on obtient une exception. Il faut donc mettre chaque appel à setpriority() au sein d un bloc try/catch de façon à gérer les exceptions éventuelles. 3) Unicité de l ordonnanceur. Que se passe-t-il si l on essaie de créer deux activités d ordonnancement, donc de

Exercice 4 Perfectionnements : subtilités de l ordonnancement 5 type RoundRobinScheduler? Les deux ordonnanceurs sont alors en compétition pour ordonnancer les activités. Il ne faut donc admettre qu une seule instance de RoundRobinScheduler à la fois. Pour ce faire, créer une variable statique booléenne de RoundRobinScheduler, nommée par exemple initialized, et la tester afin d être sûr qu une instance de la classe RoundRobinScheduler n existe pas déja. Introduire une méthode statique synchronisée, nommée par exemple isinitialized(), renvoyant un booléen, qui se sert de cette variable initialized. Se servir de cette méthode dans le constructeur de RoundRobinScheduler pour générer une exception si une instance de cette classe existe déja. 4) Attente d activités. Si toutes les activités se terminent, l ordonnanceur se termine aussi. Si l on veut se servir de RoundRobinScheduler pour un serveur, l ordonnanceur doit savoir attendre les clients lorsqu il n y en a pas. Pour ce faire, il faut d abord transformer l activité scheduler (de type la classe RoundRobinScheduler) en activité démon. Une activité démon est faite pour servir les activités utilisateur (non démon). Lorsqu il y a des activités utilisateur à exécuter, la machine virtuelle Java sélectionne la prochaine activité (utilisateur ou démon) prète à s exécuter et de priorité la plus élevée. S il ne reste que des activités démon, la machine virtuelle se termine (il n y a plus de raison pour les activités démon d exister, puisqu il n y a plus d activité utilisateur à servir). L exemple typique d activité démon est le ramasse-miettes ( garbage collector ). On rend scheduler démon par un appel de la forme scheduler.setdaemon(true). Ensuite, utiliser le mécanisme d événements wait()/notify() entre addthread() et run() avec une variable booléenne, nommée par exemple needthreads. Exercice 4 Perfectionnements : subtilités de l ordonnancement Les perfectionnements réalisés ci-dessous font peu de différences dans la majorités des cas. Ils ne sont effectués que pour donner une idée de la complexité d un ordonnanceur réel. Que se passe-t-il si une des tâches entre dans l état bloqué (par exemple en attente d une ressource d entrée/sortie) pendant que l ordonnanceur est endormi? Voyons ce qui pourrait se passer dans le cas où il y a 3 activités th1, th2, th3 à ordonnancer. Supposons qu au début de l exécution de l ordonnanceur, les activités sont dans les états suivants : PRIORITE 2 : th3 -> th1 -> null PRIORITE 4 : th2 -> null BLOQUEE : scheduler -> null L activité th2 est en cours d exécution pendant que scheduler est en train de dormir. Si th2 entre dans l état bloqué, on aura la situation suivante : PRIORITE 2 : th3 -> th1 -> null PRIORITE 4 : null BLOQUEE : th2 -> scheduler -> null Ce qui signifie que th3 devient tout de suite l activité en cours d exécution, avant même le réveil de scheduler et bien qu elle soit de priorité 2. Lorsque scheduler se réveille,

6 Un ordonnanceur simple elle remet la priorité de th2 à 2, fixe la priorité de th3 à 4 et se remet en sommeil, laissant les activités dans l état suivant : PRIORITE 2 : th1 -> null PRIORITE 4 : th3 -> null BLOQUEE : th2 -> scheduler -> null Tout va bien a nouveau, jusqu à ce que ce soit au tour de th2 de s exécuter. Puisque scheduler n a aucun moyen de déterminer que th2 est bloquée, il fixe la priorité de th2 à 4 après avoir baissé celle de th3 à 2. L ordonnanceur de la machine virtuelle Java sélectionne lui une des activités en priorité 2 pour s exécuter. Toutes les activités ont effectivement eu un certain quantum de temps d exécution. Mais ce qui est arrivé est que pendant une période de temps pendant laquelle scheduler dormait, l activité th2 de priorité 4 a été bloquée et une activité de priorité 2, th3 est devenue l activité en train de s exécuter. De fait th3 a subtilisé un peu de temps CPU ; cela a pu se produire parce qu il y a eu un temps mort entre le bloquage de th2 et le réveil de scheduler. Pour palier à cet état de fait, on introduit une activité de priorité 3 (MIN_PRIORITY+2), qui va servir à indiquer que l activité de priorité 4 est bloquée. Une classe ThreadNotifier va être crée, qui hérite de Thread. L activité de type ThreadNotifier, nommée par exemple notifier, étant de priorité 3, devient l activité en cours d exécution si celle de priorité 4 se trouve bloquée. Lorsque l activité notifier s exécute elle doit prévenir scheduler de sélectionner une autre activité pour lui monter sa priorité à 4. La classe ThreadNotifier va conserver la référence scheduler comme variable d instance. Quelques aménagements vont devoir être faits dans la classe RoundRobinScheduler : Deux variables d instance private vont être ajoutées à RoundRobinScheduler : scheduler, de type Thread, l activité d ordonnancement et notifier, de type ThreadNotifier, l activité qui prévient la précédente qu une activité est bloquée. La classe RondRobinScheduler ne va plus hériter de Thread mais va implanter Runnable, puisqu il y a deux activités à gérer. Le sleep() dans run() de scheduler va être remplacé par une attente d événement via wait(int) (qui permet d attendre un nombre maximum de millisecondes). L activité scheduler se suspend (par suspend()) losrqu il n y a plus d activités à ordonnancer et se relance (par resume()) lorsqu il en réapparaît. Trois méthodes vont être ajoutées à RoundRobinScheduler : startscheduler() qui créée, met en démon et lance les deux activités scheduler et notifier, ensuite stopscheduler() qui arrête ces deux activités et enfin wakeup() qui envoie un événement via notify() à scheduler (qui l attend, bloqué, dans la méthode run()). La méthode wakeup() est appelée dans la méthode run() de notifier. Utilisant un mécanisme wait()/notify() entre les méthodes wakeup() et run() de scheduler, ces dernières vont devoir être synchronisées. Examinons l effet de l activité notification sur l ordonnancement. Supposons partir de l état suivant : PRIORITE 2 : th2 -> th3 -> null PRIORITE 3 : notifier PRIORITE 4 : th1 -> null BLOQUEE : scheduler -> null L activité scheduler est bloquée après l exécution d un wait(int). L activité th1 est celle en cours d exécution et l activité notifier exécute sa méthode run(). Lorsque th1 se trouve bloquée, on a l état suivant :

Exercice 4 Perfectionnements : subtilités de l ordonnancement 7 PRIORITE 2 : th2 -> th3 -> null PRIORITE 3 : notifier PRIORITE 4 : null BLOQUEE : th1 -> scheduler -> null L activité notifier devient celle en cours d exécution. Elle exécute la méthode void wakeup() de RoundRobinScheduler, réveillant scheduler : PRIORITE 2 : th2 -> th3 -> null PRIORITE 3 : notifier PRIORITE 4 : null PRIORITE 6 : scheduler BLOQUEE : th1 -> null L activité scheduler assigne à th1 la priorité 2, sélectionne th2 de la liste des activités, lui assigne la priorité 4 et exécute wait(int) pour rentrer à nouveau dans l état bloqué. Annexe : code d une liste circulaire Voici le code d une liste doublement chaînée circulaire. Le noeud d une telle liste est le suivant class CircularListNode { Object o; CircularListNode next; CircularListNode prev; Voici le code de la classe CircularList. class CircularListNode { Object o; CircularListNode next; CircularListNode prev; public class CircularList { private CircularListNode current; public synchronized void insert(object o) { CircularListNode tn = new CircularListNode(); tn.o = o; if (current == null) { tn.next = tn.prev = tn; current = tn; else { // Add Before Current Node tn.next = current; tn.prev = current.prev; current.prev.next = tn; current.prev = tn; public synchronized void delete(object o) { CircularListNode p = find(o);

8 Un ordonnanceur simple CircularListNode next = p.next; CircularListNode prev = p.prev; if (p == p.next) { // Last Object on the list current = null; return; prev.next = next; next.prev = prev; if (current == p) current = next; private CircularListNode find(object o) { CircularListNode p = current; if (p == null) throw new IllegalArgumentException(); do { if (p.o == o) return p; p = p.next; while (p!= current); throw new IllegalArgumentException(); public synchronized Object locate(object o) { CircularListNode p = current; do { if (p.o.equals(o)) return p.o; p = p.next; while (p!= current); throw new IllegalArgumentException(); public synchronized Object getnext() { if (current == null) return null; current = current.next; return current.o; On dispose des méthodes suivantes : Les méthodes insert() et delete() servent à insérer une élément dans la liste et à en retirer un. La méthode locate() sert à trouver un élément en comparant le contenu (via la méthode equals()) de l élément appelant à un élément fourni en paramètre. La méthode getnext() renvoie une référence sur l objet suivant dans la liste. La méthode find() est déclarée private et n est donc pas accessible en dehors de cette classe.