Vous êtes sur la page 1sur 37

Institut Supérieur d’informatique du kef Université Jendouba

Les systèmes distribués

Master SIW 2

Enseignante : Wafa Najjar Rabai

1
Chapitre 1 : Les architectures des systèmes

I. Systèmes centralisés :
Un système centralisé c'est un système où tout le monde dépend d'une même autorité, un
serveur a priori dans le cas informatique. En informatique, un serveur central centralise un
service. Les serveurs centraux sont utilisés généralement dans une architecture centralisée a
contrario d'une architecture décentralisée (dite distribuée). On parle de serveur central dans un
réseau d'utilisateurs ou de machines. Il existe différents types de centralisation :

 la centralisation de données - qui stocke l'ensemble des données sur un serveur concernant
l'ensemble des éléments du réseau informatique ;
 la centralisation de direction - où un seul serveur décide de quel machine ou quel
utilisateur fait quoi et quand ;
 la centralisation de communication - toutes les communications passent par le serveur
central.

La centralisation de données, de direction et de communication était à l'origine la principale


organisation des réseaux informatiques.
Durant les années 1990 le serveur central a subi un changement. En effet il n'est plus seul, il
existe des serveurs de proximité (ex: serveur mandataire) des serveurs de
sauvegarde (ex: serveur de stockage en réseau) qui travaillent les uns avec les autres. Il
n'organise plus réellement le réseau, il ne centralise plus les données, ni les communications.
Le serveur central n'a vocation que de référencement. C'est-à-dire qu'il référence l'ensemble
des serveurs afin que ceux-ci puissent avoir connaissance des autres. En fait, le serveur central
est passé de machine à tout faire à annuaire central.
Durant les années 2000, après le développement de la micro-informatique (années 1980), le
développement de l'utilisation d'internet nécessite à l'utilisation de nombreux serveurs
informatique centraux (par exemple pour héberger un serveur HTTP). C'est ainsi les
utilisateurs finaux redeviennent usagers de serveurs, par exemple lors de l'utilisation
d'applications web (ex: messagerie web).

II. Systèmes distribués :


L’architecture d'un environnement informatique ou d'un réseau est dite distribuée quand
toutes les ressources ne se trouvent pas au même endroit ou sur la même machine. On parle
également d'informatique distribuée. Ce concept s'oppose à celui d'architecture
centralisée dont une version est l'architecture client-serveur.
Internet est un exemple de réseau distribué puisqu'il ne possède aucun nœud central. Les
architectures distribuées reposent sur la possibilité d'utiliser des objets qui s'exécutent sur des
machines réparties sur le réseau et communiquent par messages au travers du réseau.
II.1 L’évolution des architectures distribuées

Chapitre 1 : Les systèmes distribués 2


Au début de l'informatique, le dialogue entre machines nécessitait une connaissance
approfondie des protocoles réseau et parfois même du matériel réseau. La programmation
orientée objet a permis le développement des architectures distribuées en fournissant
des bibliothèques de haut-niveau pour faire dialoguer des objets répartis sur des machines
différentes entre eux, ce qui a considérablement allégé le travail des programmeurs. Les objets
distribués sur le réseau communiquent par messages en s'appuyant sur l'une des technologies
suivantes :
Common Object Request Broker Architecture ou CORBA : ce standard de l'Object
Management Group permet de faire communiquer des objets écrits dans des langages
différents (C++, Java, Smalltalk) et même d'encapsuler des programmes écrits dans des
langages procéduraux pour les faire passer pour des objets ;
Remote Method Invocation ou RMI : cette technologie de Sun permet de faire communiquer
très simplement des objets java distribués sur le réseau ;Les services web XML ;.NET
Remoting ;
Windows Communication Foundation.
Le seul fait de distribuer les traitements sur les ordinateurs d'un réseau augmente les
ressources disponibles. En théorie, si le réseau est internet, tous les ordinateurs connectés
constituent les ressources potentielles. C'est le sens du slogan deSun : « The network is the
computer » (« Le réseau, c'est l'ordinateur »). Les projets de calcul réparti tirent parti de cette
formidable ressource de processeurs que sont les ordinateurs inactifs connectés à internet.
II.2 La répartition des données et des services
Une architecture distribuée courante est l'architecture trois tiers à la base de la plupart des
applications distribuées de commerce électronique. Cette architecture permet d'interroger et
de mettre à jour des sources de données réparties. Les services web permettent de faire appel à
différents serveurs pour enrichir une prestation (l'achat d'un séjour touristique peut
comprendre l'achat d'un billet d'avion, d'un séjour hôtelier et d'une assurance annulation
auprès de différents vendeurs par l'intermédiaire de services web, donc d'objets distribués sur
les réseaux et dialoguant par des messages.
 Le peer-to-peer (ou poste à poste)
 Le modèle peer-to-peer (partage de fichiers) est un exemple de réussite des
architectures distribuées où chaque ordinateur est à la fois serveur de données et client
des autres. Ce modèle peut être appliqué au partage de ressource.
II.3 Les perspectives des architectures distribuées
L’une des évolutions attendues dans les temps à venir est le remplacement des achats de
logiciels informatiques par des locations de ces mêmes logiciels, pour le temps nécessaire à
leur utilisation. On peut imaginer, par exemple, qu'il sera possible, à partir d'un logiciel de
traitement de texte, de faire appel à différents services de corrections orthographiques
disponibles sur Internet, et dont on louera les services selon les besoins.
II.4 Le besoin des architectures distribuées
Un système distribué sert à faire croire qu’un ensemble de machines se comportent comme
une seule machine. Il ressemble à un seul système mais réellement c’est un système réparti
dans le but d’acquérir une vitesse plus importante et d’être plus performant.

Chapitre 1 : Les systèmes distribués 3


Exemple : une société a une base de données placée dans une seule machine. Le nombre de
clients augmente. Si la machine tombe en panne on n’a plus de services. On va partager la
charge sur deux machines pour gérer ce nombre croissant de clients. On se propose de diviser
la base en deux et d’utiliser l’alphabet donc machine 1 regroupe les clients de A à K et
machine 2 regroupe les clients J à Z . Par conséquent les systèmes doivent être synchronisés.
III. Caractéristiques des Systèmes distribués :
Pour avoir des systèmes distribués on a besoin d’accomplir les tâches suivantes :

 Augmenter les performances


 Synchroniser les données
 Gérer les écritures concurrentes
 Synchroniser les données

III.1 La performance :
a) Répartition des données
Un système devient plus performant lorsqu’on distribue les données sur plusieurs serveurs
(Fig1). On va distribuer les données sur plusieurs serveurs au lieu d’un seul serveur qui
héberge la base de données. On aura plusieurs machines et chacun héberge une partie de la
base de données. On monte en capacité de stockage. On a besoin de machines serveurs avec
des processeurs performants (5 Ghz). Si on atteint la limite du processeur il faut utiliser des
applications multithreadées c’est-à-dire plusieurs processeurs qui font la tâche donc on a une
seule machine avec plusieurs processeurs. On aura un système distribué au niveau processeur.
D’autre part on va avoir un nombre élevé de tâches donc on va opter à les répartir.
Une condition doit être satisfaite est que les données soient en bloc indépendants. Si on
exécute une requête sur plusieurs machines on doit par la suite récupérer le résultat final.
Exemple : si on cherche les dix plus gros utilisateurs (on fait un filtrage). On cherche les dix
sur chaque machine mais il y’a un qui n’apparait pas donc on cherche les cents utilisateurs sur
chaque serveur puis on trouve les dix premiers.

Chapitre 1 : Les systèmes distribués 4


Figure 1 : Distribuer les données

b) Distribution des fonctions


La distribution des fonctions consiste à subdiviser les fonctions (fig 2). On prend l’exemple
d’un serveur qui répond à une demande. Cette demande consiste à récupérer un mail, le mettre
en forme et l’envoyer. Pour répartir les fonctions on utilise quatre machines : une première
reçoit la demande puis une autre récupère le mail, la troisième va le mettre en forme puis la
dernière va rendre le service. Au niveau de la figure 2 on a une solution qui utilise une chaine
formée de 4 serveurs pour répondre à une requête et une autre solution qui utilise une
architecture plus complexe pour diminuer le chemin.
Contraintes
 Il faut noter que pour utiliser ses architectures il faut que les fonctions soient
indépendantes. Pour l’exemple du mail il faut que la mise en forme soit
indépendante des autres processus.
 On doit avoir peu de données à échanger. Pour l’exemple du mail si la source est
de 1Ko et les données intermédiaires vont atteindre 100Mo (des calculs, des
tableaux), on est face à une quantité élevée entre les serveurs ce qui peut causer
des temps de latence plus important.
 Le temps d’exécution doit être supérieur au temps de transfert sinon ça sera sans
utilité l’utilisation de la distribution des fonctions.
 Il faut que toute la chaine soit disponible. Si on a une faille dans la chaine on va
perdre tout.

Figure 2 Distribuer les fonctions

Chapitre 1 : Les systèmes distribués 5


c) Distribution les requêtes
Dans des systèmes on gère une quantité de données petite mais la charge vient du fait que
plusieurs utilisateurs sont en train d’interagir avec le système. La solution est de mettre
plusieurs nœuds (Figure 3) et on va répartir la charge sur les différents nœuds qui sont les
serveurs. On apporte une puissance de calcul plus importante et une bande passante
meilleure. On doit avoir des données qui varient peu et un mécanisme de synchronisation
de données et requêtes indépendantes. La seule contrainte est que chaque serveur doit
pouvoir héberger toutes les données.

Figure 3 Distribuer les requêtes

III.2 La gestion des écritures concurrentes :


Les écritures concurrentes peuvent causer des conflits. On prend le cas d’un user qui veut
mettre le message à B et l’autre à C. Cette modification crée un conflit car on n’a pas une
synchronisation parfaite et on ne bloque pas tout l’état du système pendant la mise à jour. Les
deux nœuds acceptent la donnée et lorsqu’on va propager l’information on aura des valeurs
différentes (Figure 4) donc un conflit. La solution est d’utiliser le temps, si une modification
intervient dans un intervalle inférieur à 1 microseconde on va le rejeter et utiliser la technique
Master/Slave (Figure 5). Le master est le seul capable d’écrire par contre le slave ne fait que
la lecture.
Si on a deux écritures au niveau du master, soit on rejette les deux soit on les met dans une
file d’attente et on va les appliquer l’une après l’autre. Ce concept est utilisé dans les systèmes
distribués. On aura un seul nœud responsable des écritures et tous les autres nœuds répondent
à la modification en lecture. On aura :
 Une seule source de modification
 Pas de conflit
 Débit d’écriture limité par la puissance d’un seul nœud
En cas de perte du primaire un secondaire est promu au rôle de master

Chapitre 1 : Les systèmes distribués 6


Figure 4 Apparition de conflits entre les nœuds

Figure 5 Architecture Master /Slave

Chapitre 1 : Les systèmes distribués 7


III.3 Synchroniser les données :

La mise à jour se fait en parallèle sur tous les nœuds donc un utilisateur
(administrateur) fait une demande d’écriture. On va arrêter les requêtes puis exécuter la
demande. On va répliquer l’information sur toutes les bases. On acquitte l’écriture à
l’utilisateur et on permet l’accès à cette donnée entre temps il faut arrêter toutes les requêtes.
Pour assurer la cohérence on procède à mettre à jour nœud par nœud sans bloquer tout le
système. On est proche du temps réel. On veut garantir que les résultats représentent l’état du
système à un instant t-Δt avec Δt 0. Par conséquent on aura un fonctionnement presque
asynchrone . Il faut noter que plus Δt autorisé est grand plus on améliore les performances.

Figure 6 Synchronisation parfaite

Figure 7 Etapes pour assurer la synchronisation parfaite

Chapitre 1 : Les systèmes distribués 8


III.3 Moyens pour synchroniser les données :
Solution avantages inconvénients
Ressource centrale  Simple à mettre en  Charge importante
place sur le serveur
 Pas de limitation central
sur les ressources  Charge réseau
 Fonctionne même importante
avec des nœuds en  Dépendance d’un
WAN seul serveur

Multicast  Utilisation de  Pas de retour


l’infrastructure réseau d’informations
 Un seul envoi  Risque de perte
 Ajout simple de de paquets
nouveaux nœuds  Montée en
charge
compliqué
 Limité à un seul
Datacenter
(LAN)

TCP Full mesh  Synchronisation  Quantité de


rapide données
 Détection rapide importantes
des erreurs  Nombre de
 Acquittements de sessions TCP
tous les échanges importants
 Convergence
rapide (temps
réseau)

Tableau 1 : Solutions proposées pour la synchronisation

Chapitre 1 : Les systèmes distribués 9


Chapitre 2 : les architectures

I. Qu’est-ce qu’un processeur ?

Le processeur ou CPU (Central Processing Unit) est le qui exécute les instructions qui lui
sont données par votre système d’exploitation (Windows). Quand vous lancez un logiciel,
regardez une vidéo Haute Définition ou lorsque vous jouez à un jeu vidéo, vous faites
travailler en priorité le processeur ! Pour répondre à vos demandes les plus exigeantes,
le processeur peut être doté des plusieurs cœurs.

II. Qu’est-ce qu’un monoprocesseur ?

Plusieurs instructions peuvent être traitées par le cœur d’un processeur mais ce sera
toujours une par une, en série. Avant l’apparition des processeurs multi-cœurs, on avait
l’impression que les processeurs simple cœur étaient multi-tâches tellement ils passaient
d’une instruction à une autre rapidement mais il n’en était rien.

On parle alors de processeur SISD, signifiant single instruction single data stream. La
plupart des ordinateurs monoprocesseurs conventionnels (par exemple IBM 370, DEC VAX,
SUN) fonctionnent, plus ou moins, sur ce principe. À chaque cycle d'horloge, l'unité logique et
arithmétique (ULA) du processeur exécute une opération élémentaire indiquée par le
programme-machine. Si par exemple on veut ajouter deux nombres, d'abord l'adresse
mémoire du premier est mise dans un registre lu par le processeur pour aller chercher à la
bonne place de la mémoire RAM ; ensuite le nombre est rappelé de la mémoire dans le registre
d'addition. La même opération est recommencée avec l'autre opérande. Ensuite, l'opération
d'addition est exécutée, le résultat remplace le contenu du registre correspondant et finalement
est sauvé dans la mémoire RAM. Évidemment, les registres, qui sont des mémoires très
rapides, ne peuvent contenir qu'une très petite quantité de données et rappeler chaque fois que
le besoin se présente la donnée nécessaire. Comme les accès à la mémoire RAM sont plus lents
que les accès des registres, plusieurs cycles d'horloge s'écoulent pour le rappel des données
pendant lesquels le processeur reste inactif. Quelques règles de bon sens et l'utilisation des
compilateurs de plus en plus optimisés peuvent minimiser ce va-et-vient incessant.

Une avancée révolutionnaire fut la conception et la réalisation des premiers processeurs


vectoriels. Pour comprendre leur mode de fonctionnement, imaginons que l'on veuille ajouter
deux vecteurs, ce qu'en FORTRAN, par exemple, est effectué par la boucle.

Si l'addition de deux nombres scalaires nécessite des cycles d'horloge, l'addition de deux
vecteurs à composantes nécessite cycles sur un processeur scalaire. En effet, la boucle
précédente est décomposée en instructions machine plus élémentaires pour sommer deux à
deux chaque élément.

Il est donc évident pourquoi l'addition de deux vecteurs nécessite plusieurs cycles sur un
processeur scalaire. Les processeurs vectoriels disposent, outre les registres scalaires, des
registres vectoriels dont les contenus peuvent être additionnés ou multipliés en un cycle. Si

Chap2 : Les architectures 10


donc les registres vectoriels sont suffisamment grands pour contenir les composantes d'un
vecteur, la boucle ci-dessus ne nécessitera que cycles, autant que l'addition de deux nombres.
On parle alors d'architecture SIMD qui signifie single instruction multiple data stream. Des
ordinateurs monoprocesseurs vectoriels (comme le CRAY 1) ou matriciels (comme le FPS)
fonctionnent sur ce principe. On constate donc qu'on a un gain de temps spectaculaire s'il est
possible de faire subir la même opération à toutes les composantes d'un vecteur sur un
processeur vectoriel. On dit alors que l'algorithme est vectorisable.

III. . Qu’est-ce qu’un multiprocesseur ?

Dans la course vers la performance calculatoire, les ordinateurs parallèles furent l'étape
de sophistication suivante. Dans cette architecture, plusieurs processeurs exécutent des tâches
identiques ou comparables sur des données partagées tant qu'il n'y ait pas de conflit d'accès et
de préséance des opérations sur les données partagées. Cette architecture est appelée MIMD de
multiple instruction multiple data stream. Des ordinateurs multiprocesseurs avec des
mémoires partagées (comme le SYMMETRY) ou des systèmes avec des mémoires locales
(comme l'Intel iPSC) fonctionnent sur ce principe.

Pour une taxonomie plus approfondie sur les diverses architectures, on peut consulter l'article
de [FLYNN]. Paradoxalement, aujourd'hui la technologie avance plus rapidement que la
conception de nouveaux algorithmes parallèles efficaces.

IV. Classification de FLYNN


1. SISD (unique flux d'instructions, unique flux de données).Il s'agit d'un ordinateur
séquentiel qui n'exploite aucun parallélisme, tant au niveau des instructions qu'au niveau
de la mémoire. Cette catégorie correspond à l'architecture de von Neumann.
2. SIMD (unique flux d'instructions, multiples flux de données).
Il s'agit d'un ordinateur qui utilise le parallélisme au niveau de la mémoire, par exemple
le processeur vectoriel.
3. MISD (multiples flux d'instructions, unique flux de données)
Il s'agit d'un ordinateur dans lequel une même donnée est traitée par plusieurs unités de
calcul en parallèle. Il existe peu d'implémentations en pratique. Cette catégorie peut être
utilisée dans le filtrage numérique et la vérification de redondance dans les systèmes
critiques.
4. MIMD (multiples flux d'instructions, multiples flux de données)
Dans ce cas, plusieurs unités de calcul traitent des données différentes, car chacune d'elles
possède une mémoire distincte. Il s'agit de l'architecture parallèle la plus utilisée. dont les
deux principales variantes rencontrées sont les suivantes :
 MIMD à mémoire partagée
Les unités de calcul ont accès à la mémoire comme un espace d'adressage global. Tout
changement dans une case mémoire est vu par les autres unités de calcul. La
communication entre les unités de calcul est effectuée via la mémoire globale.

Chap2 : Les architectures 11


 MIMD à mémoire distribuée
Chaque unité de calcul possède sa propre mémoire et son propre système
d'exploitation. Ce second cas de figure nécessite un middleware pour la
synchronisation et la communication.
Un système MIMD hybride est l'architecture la plus utilisée par les superordinateurs.
Ces systèmes hybrides possèdent l'avantage d'être très extensibles, performants et à
faible coût

Single Instruction Single Data

Une instruction

Un flot de données

Ordinateur séquentiel

Pas de parallélisme

NB : PU Processus Unifié c’est


une unité de calcul d’un
processeur unicoeur ou
multicoeur

Single Instruction Multiple Data

Le processeur est dit vectoriel. Il


possède des registres vectoriels
dont les contenus peuvent être
additionnés ou multipliés en un
cycle ce qui permet un gain de
temps. Les ordinateurs sont
appelés monoprocesseurs vecto-
riels. Ils utilisent le parallélisme
au niveau mémoire

Chap2 : Les architectures 12


Multiple Instruction Single Data

Les instructions sont différentes


mais on traite les mêmes données.

Tolère les pannes

Exemple :

Contrôleur navette spatiale

Multiple Instruction Multiple Data

Différentes Instructions Différentes


données comprend deux sous
groupes :

SPMD : le même programme est


exécuté sur les différentes unités
mais de manière indépendante

MPMD : différents programmes


sont exécutés sur les différentes
unités

Le modèle SPMD utilise la parallélisation dans la mémoire. Les deux principales


variantes rencontrées sont les suivantes :
 MIMD à mémoire partagée
Les unités de calcul ont accès à la mémoire comme un espace d'adressage global. Tout
changement dans une case mémoire est vu par les autres unités de calcul. La
communication entre les unités de calcul est effectuée via la mémoire globale. On a un
faible surcout de parallélisation. Le nombre de processeurs est <64 . Cette architecture
est coûteuse. On la nomme de Symmetric (shared-memory) multiprocessor (SMP). Si
on augmente le nombre de processeurs la mémoire devient le goulot d’étranglement,
pour cela on passe de la mémoire centralisée à la mémoire distribuée.
Chap2 : Les architectures 13
 MIMD à mémoire distribuée
Chaque unité de calcul possède sa propre mémoire et son propre système
d'exploitation. Ce second cas de figure nécessite un middleware pour la
synchronisation et la communication. On utilise un plus grand nombre de processeurs.
Cette architecture met en jeu des réseaux d’interconnexion directs avec des
commutateurs ou indirects avec des grilles multidirectionnelles.
Un système MIMD hybride est l'architecture la plus utilisée par les superordinateurs.
Ces systèmes hybrides possèdent l'avantage d'être très extensibles, performants et à
faible coût

V. Qu’est-ce qu’un processeur multi-cœurs ?

Un processeur multi-cœur est composé de deux ou plusieurs cœurs indépendants,


chacun étant capable de traiter des instructions individuellement. Un processeur dual-
core contient deux cœurs, un processeur quad-core quatre cœurs, un processeur hexa-
core six cœurs
A quoi peut me servir plusieurs cœurs ?
Un processeur multi-cœur permet à l’utilisateur d’exécuter plusieurs tâches en même
temps sans subir de ralentissements ! Autrement dit, les cœurs sont utiles si vous utilisez
plusieurs logiciels à la fois. Quand un programme est en cours d’exécution (logiciel de
montage vidéo ou de retouche photo par exemple) et traité par un cœur, vous pouvez
solliciter un autre cœur pour utiliser votre navigateur internet ou écrire un document.
Avoir plusieurs cœurs est aussi utile lorsque vous utilisez un logiciel qui peut utiliser plus
d’un cœur. En effet, la majorité des programmes est conçue pour n’utiliser qu’un seul et
unique cœur. Un logiciel qui est compatible avec le multi-cœur fonctionne lui beaucoup plus
rapidement puisqu’il peut exécuter plusieurs instructions en même temps. C’est le cas
notamment des logiciels de retouche photo ou les jeux vidéo.
Si vous n’utilisez votre ordinateur que pour consulter vos mails ou regarder des vidéos, vous
n’avez pas vraiment besoin d’un processeur avec beaucoup de cœurs.
Les cœurs sont-ils révélateurs de la puissance d’un processeur ?

Chap2 : Les architectures 14


Oui, mais ce n’est pas le seul indicateur ! Le nombre de cœurs est certes le premier
indicateur de la puissance d’un processeur mais il ne faut pas se focaliser uniquement sur
cette donnée. Nous allons voir dans la suite de ce dossier qu’il faut regarder d’autres
caractéristiques, notamment chez les processeurs Intel Core i3, i5 et i7  : la fréquence, la
mémoire cache, les technologies utilisées…
Les processeurs Intel Core ne date pas d’hier ! La première génération de ces
processeurs est en effet apparue en 2008. Depuis, les Intel Core se sont considérablement
améliorés : de nouvelles technologies, de meilleures performances, des graphismes largement
optimisés… Aujourd’hui en 2016, nous en sommes à la sixième génération Skylake. 

Quels sont les différences entre multicoeurs et multiprocesseurs ?

Il semble que la question se pose à une époque où il existe encore des machines
multiprocesseurs de la génération antérieure avec des processeurs double cœurs de la
génération en cours (quadcore d’Intel) ou les multiprocesseurs à base de multicoeurs.
Les questions légitimes portent la plupart du temps sur l’aspect performance des choses, et de
faire une comparaison entre les deux architectures comme si il suffisait de faire l’équation
Deux Cœurs = Deux processeurs Simple Cœur, alors que rien n’est moins évident que ce
raccourci et ce autant au niveau matériel que logiciel même…
Commençons d’un point de vue basique, tout le monde peut imaginer assez facilement
qu’entre une machine avec une carte mère ayant plusieurs emplacements pour des processeurs
et une avec un seul il y a des différences techniques qui peuvent déjà commencer à expliquer
les différences de performance entre les deux plateformes.
La première différence concerne les échanges d’informations entre les processeurs, sur une
carte mère multiprocesseur, c’est à elle qu’incombe ces échanges, et c’est par son
intermédiaire qu’ils seront réalisés. Bien entendu et malgré les différentes plateformes
technologiques existantes, les canaux utilisés sont beaucoup plus petits et lents que ne le sont
ceux existant entre deux cœurs sur une même puce.
En effet les échanges entre cœurs sont souvent faits à la vitesse du processeur et souvent sur
des liaisons internes à très grande vitesse.
A propos d’échanges, une différence existe aussi concernant les accès mémoire puisque c’est
le processeur qui les gère sur une machine multicoeurs, ils sont plus facilement accessibles et
les chevauchements sont gérés par le processeur pour éviter que les données ne soient lus ou
écrites à des endroits où d’autres cœurs sont en train de lire ou d’écrire.
Dans le cas du multiprocesseur, c’est la carte mère et son chipset qui gère ceci, et là encore les
goulots d’étranglement sont dans les canaux utilisés pour gérer ça.

Chap2 : Les architectures 15


Une autre des différences concerne la consommation électrique qui est moindre sur une
machine uniprocesseur quand bien même il contient plusieurs cœurs.

Concernant maintenant l’utilisation de tous les jours, quelles sont les différences et surtout
laquelle des différentes plateformes peut être la plus performante?
Tout d’abord il faut savoir qu’une limitation existe suivant le système d’exploitation et du
nombre de processeurs, en effet que ça soit sur des systèmes Windows serveur ou même
Vista, le prix entre une version monoprocesseur (voir parfois biprocesseurs) et
multiprocesseurs et sans commune mesure.
Mais il faut savoir que pour Microsoft un processeur double ou quadruple cœurs n’est rien
d’autre qu’un processeur unique (ce qui est physiquement exact puisque chaque cœur n’est en
fait qu’une unité de calcul et pas un processeur à part entière) et donc que vous pouvez utiliser
un Vista standard sur une machine quadruple cœurs, alors que sur une machine
multiprocesseurs vous devrez vous acquitter d’une version spéciale sans quoi un seul des
processeurs sera pris en compte.
A l’époque ou n’existait pas les multicoeurs, le multitâche était produit par ce que l’on appelle
les threads, ces processus partagent le temps processeur de manière équitable en fonction des
priorités et des nécessités, chaque thread utilisation quelques microsecondes avant de laisser
la main au thread suivant.
Dans tous les systèmes récents, ces threads sont au cœur même du système, une des
différences entre multicoeurs et multiprocesseurs consiste en la répartition de ces threads
entre les unités de calcul, en effet concernant le multiprocesseur, il faut que le système assure
correctement la répartition afin que les différents processeurs soient utilisés à leur maximum
de performance.
Concernant les logiciels aussi, il faut qu’ils utilisent des instructions particulières du système
de manière à faire répartir justement les traitements correctement entre les différents
processeurs, alors que dans le cas du multicoeur, c’est lui qui assure ce travail et qui réparti
justement entre les différents cœurs en fonction du traitement.
Et c’est là l’une des différences essentielle qui fait que pour une utilisation classique d’un
ordinateur (pas une utilisation professionnelle ou spécifique comme un serveur) une machine
multicoeur est plus performante puisque elle optimise en temps réel la charge sur les
différents cœurs.
Ces différences sont bien entendu réduites pour peu que l’on utilise un système réellement
multiprocesseur et des logiciels eux aussi conçus et programmés pour prendre en compte
plusieurs processeurs physiques.

Les multicoeurs vont devenir de plus en plus courants et ce pour plusieurs raisons qui sont
une question de coût, un multicoeur coutant moins à fabriquer que deux processeurs par
exemple. De plus leur puissance fait qu’ils sont un choix bien plus intéressant.
D’ailleurs les machines multiprocesseurs à base de processeurs multicoeurs sont aussi l’avenir
des solutions nécessitant une puissance de calcul importante comme pour les serveurs et leurs
applications diverses.
Ce petit laïus n’est pas exhaustif, il ne couvre pas toutes les différences, mais permet de se
faire une idée assez précise, de tout temps les gens ont toujours été attirés par les
multiprocesseurs, mais il est de cette attirance comme de beaucoup de mythe elle ne repose
que sur le fait que les systèmes multiprocesseurs sont plus rares et plus chers, mais pour les
particuliers ils ne sont et ne seront jamais d’une utilité quelconque, sauf dans le cas ou ces
machines sont utilisées pour leurs réels objectifs et sur des systèmes adéquats.

VI. Le multithreading
Chap2 : Les architectures 16
1. Parallélisme et concurrence

On dit que deux processus s'exécutent en parallèle lorsqu'ils s'exécutent sur des CPU
différents. Ils sont concurrents lorsqu'ils concourent pour l'obtention d'une même ressource
CPU. Leur exécution est alors entrelacée. Chacun dispose à son tour d'un quantum de temps
calcul.

2. Définition du thread :

 Un thread est un flot de contrôle à l'intérieur d'un programme. On parle de fil


d'exécution, de processus léger ou même d'activité.
 Contrairement aux processus, les threads partagent le même espace d'adressage, le
même environnement (variables d'environnement, fichiers,...).
 Un thread possède donc moins de ressources propres qu'un processus. Sa gestion est
moins coûteuse.
La JVM (Java Virtual Machine) est un exemple de programme multi-threadé

3. Fonctionnement du thread :

 La ressource CPU doit être partagée de manière équilibrée entre les différents threads
et l’ordonnanceur gère cette répartition.
 L’algorithme de l’ordonnanceur diffère selon les plate-formes (Unix, Windows,
Macintosh)
 Pour un CPU unique, il fonctionne en accordant successivement à chaque thread un
quantum de temps
 Chaque thread (processus léger) possède une priorité propre (attribuée par défaut ou
bien choisie par le programmeur). La priorité varie de 1 à 10 (par défaut 5). La
méthode setPriority(int p) permet de fixer la priorité.
 L'ordonnanceur attribue généralement le CPU au processus de plus forte priorité. Dès
qu'un quantum se termine, le processus auquel avait été attribué ce quantum, est de
nouveau en compétition pour l'attribution du CPU pendant que le processus de plus
forte priorité reçoit le CPU.
 A tout moment, un processus peut décider lui-même de céder le CPU pour donner une
chance aux autres de s'exécuter.

Chap2 : Les architectures 17


Chapitre 3 : Les systèmes distribués
I. Les systèmes embarqués
Un système embarqué peut être défini comme un système électronique et informatique
autonome, qui est dédiée à une tâche bien précise. Ses ressources disponibles sont
généralement limitées. Cette limitation est généralement d’ordre spatial (taille limitée) et
énergétique (consommation restreinte).Les systèmes embarqués font souvent appel à
l’informatique et notamment aux systèmes temps réel. Le terme de système embarqué
désigne aussi bien le matériel que le logiciel utilisé.
Les systèmes embarqués sont étudiés pour effectuer des tâches précises. Certains doivent
répondre à des contraintes de temps réel pour des raisons de sécurité et de rentabilité. D’autres
ayant peu de contraintes au niveau performances permettent de simplifier le système et de
réduire les couts de fabrication. Les systèmes embarqués sont intégrées dans le dispositif
qu’ils contrôlent. L’architecture embarquée est composée d’un ensemble de calculateurs reliés
entre eux. L’application est morcelée et chaque calculateur implante un ensemble de
fonctionnalités. Le principal intérêt est de permettre un rapprochement entre les calculateurs,
les capteurs et les actionneurs. La réduction des câblages ainsi obtenue permet non seulement
de limiter les coûts, mais aussi d’augmenter la fiabilité du système. La conception de ce type
de système est simplifiée car elle revient à réaliser plusieurs systèmes temps réel plus simples.
Parmi les systèmes embarqués on distingue habituellement deux types d’architectures.

1. Architecture embarquée faiblement distribuée

Au début des années 80, des bus de terrain ont été développés par les constructeurs
automobiles et équipementiers : bus CAN par Bosch, Van par Renault et J1850 par les
constructeurs américains. Ces bus filaires dédiés aux environnements perturbés tels que les
automobiles permettent de relier entre eux les calculateurs. Grâce à ses bus, les applications
temps réel embarquées des architectures que l’on qualifie ici de faiblement distribuées. Elles
sont constituées d’un ensemble de calculateurs et il est possible de partager des capteurs et
actionneurs entre les calculateurs.
2. Architecture embarquée fortement distribuée

Les capteurs et actionneurs deviennent intelligents, ils peuvent directement être connectés sur
le bus. Cette approche permet de réduire considérablement tous les câblages, car tous les
organes électriques du système embarqué peuvent être reliés au bus. C’est aussi l’approche la
plus complexe à mettre en œuvre au niveau logiciel. Il faut gérer efficacement le multiplexage
des données issues des capteurs et des calculateurs sur le bus de telle sorte que les contraintes
temporelles de chacun des signaux soient satisfaites.
Les architectures temps réels réel embarqués sont actuellement non seulement fortement
distribuées, mais elles sont aussi hétérogènes. Une même application peut intégrer une dizaine
de calculateurs. Pour garantir une exécution temps réel des algorithmes il est parfois
nécessaire de disposer d’une grande puissance de calcul fournie par exemple par des Digital
Signal Processor ou des microprocesseurs performants. Certaines fonctions peuvent aussi être
programmées sur des FPGA ou des ASIC. Des microcontrôleurs sont aussi utilisés pour leur
capacité à gérer un grand nombre d’entrées et de sorties avec un minimum de composants
périphériques

Chap3 : Les systèmes distribués 18


3. Exemples de systèmes embarqués :
a. Véhicule

Figure 1 : Système embarqué

b. Système de Vidéo conférence sur réseau local

 Numérisation du signal vidéo

 Séquence de 30 images/s

 Compression Réseau Accès, envoi, réception

II. Les systèmes temps réels :


1. Définition

En informatique, on parle d'un système temps réel lorsque ce système est capable de


contrôler (ou piloter) un procédé physique à une vitesse adaptée à l'évolution du procédé
contrôlé.
Les systèmes informatiques temps réel se différencient des autres systèmes informatiques
par la prise en compte de contraintes temporelles dont le respect est aussi important que
l'exactitude du résultat, autrement dit le système ne doit pas simplement délivrer des
résultats exacts, il doit les délivrer dans des délais imposés.
2. Domaines d’applications

Les systèmes informatiques temps réel sont aujourd'hui présents dans de nombreux secteurs
d'activités :

Chap3 : Les systèmes distribués 19


 l'industrie de production par exemple, au travers des systèmes de contrôle de procédé
(usines, centrales nucléaires) ;
 les salles de marché au travers du traitement des données boursières en « temps réel » ;
 l'aéronautique au travers des systèmes de pilotage embarqués (avions, satellites) ;
 l’automobile avec le contrôle de plus en plus complet des paramètres moteur, de la
trajectoire, du freinage, etc. ;
 le secteur de la nouvelle économie au travers du besoin, toujours croissant, du traitement
et de l'acheminement de l'information (vidéo, données, pilotage à distance, réalité
virtuelle, etc.).
Le développement de systèmes temps réel nécessite donc que chacun des éléments du système
soit lui-même temps réel, c’est-à-dire permettre de prendre en compte des contraintes
temporelles et la priorité de chacune des taches. Un système d'exploitation conçu pour prendre
en compte ces contraintes est appelé système d'exploitation temps réel
3. Classification des systèmes temps réel
 Temps réel dur (‘hard real-time’) : le non-respect des contraintes temporelles entraîne la
faute du système – e.g. contrôle de trafic aérien, système de conduite de missile, ...
 Temps réel souple (‘soft real-time’) : le respect des échéances est important mais le non-
respect des échéances n’a pas de graves conséquences – e.g. système d'acquisition de
données pour affichage
 Temps réel ferme (‘firm real-time’) : temps réel souple, mais si l’échéance est dépassée
le résultat obtenu n’a plus de valeur (et est donc écarté)

Chap3 : Les systèmes distribués 20


Chapitre 4 : Conception et mise en œuvre d’applications
temps réel

 Introduction :

UML2 permet de modéliser quelques aspects temps réel. UML2 ajoute des concepts de
base pouvant être utilisé pour modéliser certaines caractéristiques particulières des
applications temps réel et embarqué. Il ne satisfait pas complètement les besoins de
modélisation de ces catégories du système. Pour combler cette lacune un ensemble
d’extensions a été ajouté à UML. Les extensions courantes et normées sont dédiées à
l’analyse, la modélisation et l’implémentation d’applications temps réel et embarquées.

Figure 8 Le système temps réel et son environnement


I. Les extensions UML pour le temps réel
Les meta modèles standards UML fournit des mécanismes d’extension appelés
stéréotypes, valeur marquée (target values) et contraintes.
1. Stéréotypes :
Il représente le mécanisme de base pour l’extension UML, il définit comment une
méta classe particulière du méta modèle d’UML peut être étendu pour permettre
l’utilisation d’une terminologie ou d’une notation spécifique à un domaine ou une
plateforme particulière. Un stéréotype est lié par un lien d’extension à une méta
classe particulière du méta modèle
2. Valeur marquée :
Ce sont un moyen d’attacher des propriétés supplémentaires à un concept d’UML .
Elles sont considérées dans UML2.comme des propriétés des stéréotypes, une
valeur marquée a un nom et un type.
3. Contraintes :
Elle spécialisé la sémantique des éléments du méta modèle UML via une
expression s’appuyant sur un langage de contraintes donné.

Chap 5 : Les design Pattern pour le temps réel 21


II. Diagramme de séquence avec contraintes temporelles
On peut modéliser le temps dans un diagramme de séquence en utilisant la notation
suivante :
{<val}{a<paramètre<b}
1. Etude de cas : le téléphone analogique

On peut modéliser le temps dans le diagramme de séquence. La figure 8 décrit ce


diagramme illustrant l’utilisation des contraintes et des observations de temps.
L’exemple propose plusieurs contraintes de temps. Le destinataire doit décrocher entre 7
heures et 9 heures. Une tonalité doit être reçue moins d’une seconde après que le
destinataire a décroché. Ensuite, le premier chiffre doit être composé dans les 10 secondes.

Figure 9 Modélisation du temps dans les diagrammes de séquence.


2. Etude de cas : Régulateur d’allure capable de maintenir la vitesse

Certains véhicules sont équipés d’un système capable de réguler la vitesse courante de
la voiture autour d’une vitesse, dite vitesse de consigne. Cette vitesse est fixée par
l’utilisateur et représente la vitesse à laquelle il désire rouler automatiquement. Cet exemple
se veut simple mais cependant suffisamment représentatif des problèmes que l’on peut
rencontrer dans la modélisation d’applications embarquées pour une automobile. C’est un
système qui doit être réactif, qui présente des comportements cycliques et qui doit
être en forte interaction avec son environnement.
Le système que l’on veut réaliser est donc un régulateur d’allure capable de
maintenir la vitesse d’un véhicule à une vitesse consigne cible fixée par le
conducteur. Le maintien de la vitesse s’effectuera par envoi d’une variation de couple au
système de contrôle du moteur. La loi de commande que le régulateur d'allure
utilise pour calculer la variation du couple est la suivante :

arctan(k u (Vcible Vvéhicule))


GC
2
Ainsi, si Vcible>Vvéhicule alors GC>0et le véhicule accélère.
Sinon,
VcibledVvéhicule alors GCd0 et le véhicule
ralentit.
La mesure de la vitesse du véhicule s’effectue à l’aide d’un compteur de vitesse
pourvu de son propre système d’affichage. La mesure est réalisée de façon cyclique à la
Chap 5 : Les design Pattern pour le temps réel 22
fréquence de 2 Hz. La mise à jour de l’affichage de la vitesse s’effectue au même
rythme. On suppose que ce compteur est capable de fournir la valeur courante de la
vitesse du véhicule en m/s sous la forme d’un entier.
La mise en marche de la régulation nécessite l’allumage préalable du système
régulateur d’allure, puis l’activation de la régulation. L’allumage ou l’extinction du
régulateur d’allure s’effectuent à l’aide d’un signal émis par un bouton poussoir
Allumer/Éteindre actionné par le conducteur. Si le régulateur d’allure est allumé, il
s’éteint. Si le régulateur d’allure est éteint, il s’allume. L’action d’allumage ou
d’extinction du régulateur d’allure doit être effectuée en moins de 1s suite à une
action sur le bouton poussoir Allumer/Éteindre du régulateur d’allure.

L’activation (mise en marche) de la régulation se fait ensuite via un autre bouton


poussoir Marche/Arrêt. La régulation de la vitesse doit démarrer au plus tard 0,5s après
la demande d’activation de la régulation. La régulation du véhicule ne peut être mise en
route que si la vitesse du véhicule est au moins égale à 50 km/h et si le système
régulateur d’allure a été préalablement allumé. Lors de l’activation de la régulation, la
vitesse de consigne est définie comme égale à la vitesse courante du véhicule au moment
où la régulation est activée.

La désactivation (arrêt) de la régulation peut se faire de quatre façons différentes :


- soit implicitement, lorsque le conducteur appuie sur la pédale de frein ;
- soit explicitement par action du conducteur sur le bouton Marche/Arrêt du
régulateur d’allure ;
- soit si la vitesse du véhicule devient inférieure à 50 km/h.
- soit par extinction du régulateur d’allure via action du conducteur sur le bouton
Allumer/Eteindre du régulateur d’allure ;

Les temps de réponse attendus pour l’arrêt de la régulation sont : de 0,5 s par appui sur le
frein ou par action sur le bouton Marche/Arrêt; ou le bouton Allumer/Eteindre ; et de 100
ms si la vitesse du véhicule devient inférieure à 50 km/h.
De plus, lorsque le conducteur appuie sur la pédale d’accélération alors que la régulation est
activée, la régulation de vitesse est suspendue jusqu’à ce que le conducteur relâche
l’accélérateur. La suspension doit être réalisée en au plus 200 ms et la reprise en au
plus 250 ms. Le système reprend alors le contrôle de la vitesse du véhicule et l’amène
progressivement à la vitesse de consigne fixée avant l’accélération.
En cas de simultanéité des actions de décélération et d’accélération, c’est l’action de
décélération qui doit être prise en compte prioritairement. La régulation doit alors être
arrêtée et non suspendue avec le délai d’un arrêt par appui sur la pédale de frein.
Le régulateur d’allure est connecté à un écran qui affiche la vitesse de consigne et l’état
d’activation de la régulation (désactivée, activée ou suspendue). Il fonctionne à la demande
avec un temps de réponse attendu de 0,5 s.

Chap 5 : Les design Pattern pour le temps réel 23


Figure 10 Diagramme de séquence d’un système régulateur d’Allure
III. Les diagrammes en UML2
UML2 a modifié les diagrammes de base pour les adapter aux systèmes temps réel (cas du
diagramme de séquence). En parallèle de nouveaux diagrammes ont été créés pour assurer la
modélisation des systèmes temps réel. Ces nouveautés concernent les diagrammes de
structures et les diagrammes de comportement.

 les diagrammes de structures : on a le diagramme de composition et le diagramme


de paquetage
 les diagrammes de comportement : on a le diagramme de timing et le diagramme
d’interaction
exemple : Diagramme de timing pour la machine de préparation de café

IV. Utilisation des stéréotypes

Les valeurs de temps peuvent être représentées par un stéréotype particulier de valeurs,
appelé RTime regroupant différents formats

Chap 5 : Les design Pattern pour le temps réel 24


V. Les design Pattern pour le temps réel

1. Définition
L’origine des Design Patterns remonte au début des années 70 avec les travaux de l’architecte
Christopher Alexander. Celui-ci remarque que la phase de conception en architecture laisse
apparaître des problèmes récurrents. Il cherche alors à résoudre l’ensemble de ces problèmes
liés à des contraintes interdépendantes (solidité de la structure, étanchéité...). Pour cela
Alexander établi un langage de 253 patterns, qui couvrent tous les aspects de la construction
(comme par exemple la façon de concevoir une charpente).
Un Design Pattern est une solution à un problème récurrent dans la conception d’applications
orientées objet. Un patron de conception décrit alors la solution éprouvée pour résoudre ce
problème d’architecture de logiciel. Comme problème récurrent on trouve par exemple la
conception d’une application où il sera facile d’ajouter des fonctionnalités à une classe sans la
modifier (voir la solution du Design Pattern Visiteur). A noter qu’en se plaçant au niveau de
la conception les Design Patterns sont indépendants des langages de programmation utilisés.

Chap 5 : Les design Pattern pour le temps réel 25


Figure 11 Le Pattern

2. Représentation d’un patron de conception


Les Design Patterns sont représentés par :
 Nom : qui permet de l’identifier clairement
 Problématique : description du problème auquel il répond
 Solution : description de la solution souvent accompagnée d’un schéma UML
 Conséquences : les avantages et les inconvénients de cette solution

3. Les avantages d’un patron de conception


L’utilisation des Design Patterns offre de nombreux avantages. Tout d’abord cela
permet de répondre à un problème de conception grâce à une solution éprouvée et validée par
des experts. Ainsi on gagne en rapidité et en qualité de conception ce qui diminue également
les coûts.

De plus, les Design Patterns sont réutilisables et permettent de mettre en avant les bonnes
pratiques de conception. Les Design Patterns étant largement documentés et connus d’un
grand nombre de développeurs ils permettent également de faciliter la communication. Si un
développeur annonce que sur ce point du projet il va utiliser le Design Pattern Observateur il
est compris des informaticiens sans pour autant rentrer dans les détails de la conception
(diagramme UML, objectif visé...).

4. Organisation des patrons de conception


Les patrons de conception sont classés en trois catégories :
 Création : ils permettent d’instancier et de configurer des classes et des objets.
 Structure : ils permettent d’organiser les classes d’une application.
 Comportement : ils permettent d'organiser les objets pour qu’ils collaborent entre eux.

Chap 5 : Les design Pattern pour le temps réel 26


VI. Le profil SPT "Schedulability, Performance and Time"

Le profil SPT (Schedulability, Performance and Time) est proposé par l'OMG comme
un standard pour modéliser les systèmes temps réel [6]. Cette norme propose une façon
standard d'annoter les modèles UML avec des caractéristiques de QdS ("Qualité de
services"). Elle définit aussi une façon commune pour la représentation des informations
temporelles. Cette standardisation permet de faciliter l'interaction entre les différents
modèles UML et outils d'analyse de performance. Il est alors possible de vérifier et valider
des propriétés extra fonctionnelles comme les temps de réponse ou la taille des files
d'attente en se basant sur les données comme les échéances, le temps d’exécution de pire cas
(WCET) ou les politiques d'ordonnancement.

Le profil SPT s'articule sur trois paquetages principaux :

- Le premier paquetage, nommé GRMF (General Resource Modeling Framework),


définit un cadre générique pour supporter n’importe quel type d’analyse du modèle. Il est lui-
même constitué de trois sous –paquetages :
 sous-paquetage dédié à la modélisation des ressources (General Resource Modeling
"GRM″),
 sous-paquetage dédié à la concurrence (General Concurrency Modeling ″GCM″)
 sous paquetage du temps (pour General Time Modeling’’GTM’’).

Ces paquetages spécifient respectivement les moyens de modéliser la QdS des


ressources en considérant les propriétés physiques du logiciel et du matériel
support d’exécution d’une application temps réel, de définir le concept d’unité
concurrente et de représenter les concepts liés au temps.
- Le second grand paquetage du SPT (Analysis Models) spécialise le paquetage précédant
en utilisant les concepts génériques de façon à , d’une part définir les moyens nécessaires à
une analyse d’ordonnançabilité et d’autre part à une analyse de performances

Figure 4. Structure du profil SPT

Chap 5 : Les design Pattern pour le temps réel 27


- Le dernier paquetage (Infrastructure Models) est dédié à la description de la
p lateforme d’exécution Real Time Corba

VII. Les outils de développement UML pour les STRE

Plusieurs outils pour développer les STRE : STARUML Papyrus Poseidon ArgoUML

Diagramme de structure composite

Chap 5 : Les design Pattern pour le temps réel 28


Chapitre 5 : Les design Pattern pour le temps réel

I. Les design Pattern


1. Définition
L’origine des Design Patterns remonte au début des années 70 avec les travaux de l’architecte
Christopher Alexander. Celui-ci remarque que la phase de conception en architecture laisse
apparaître des problèmes récurrents. Il cherche alors à résoudre l’ensemble de ces problèmes
liés à des contraintes interdépendantes (solidité de la structure, étanchéité...). Pour cela
Alexander établi un langage de 253 patterns, qui couvrent tous les aspects de la construction
(comme par exemple la façon de concevoir une charpente).
Un Design Pattern est une solution à un problème récurrent dans la conception d’applications
orientées objet. Un patron de conception décrit alors la solution éprouvée pour résoudre ce
problème d’architecture de logiciel. Comme problème récurrent on trouve par exemple la
conception d’une application où il sera facile d’ajouter des fonctionnalités à une classe sans la
modifier (voir la solution du Design Pattern Visiteur). A noter qu’en se plaçant au niveau de
la conception les Design Patterns sont indépendants des langages de programmation utilisés.

2. Représentation d’un patron de conception


Les Design Patterns sont représentés par :
 Nom : qui permet de l’identifier clairement
 Problématique : description du problème auquel il répond
 Solution : description de la solution souvent accompagnée d’un schéma UML
 Conséquences : les avantages et les inconvénients de cette solution

3. Les avantages
L’utilisation des Design Patterns offre de nombreux avantages. Tout d’abord cela
permet de répondre à un problème de conception grâce à une solution éprouvée et validée par
des experts. Ainsi on gagne en rapidité et en qualité de conception ce qui diminue également
les coûts.

De plus, les Design Patterns sont réutilisables et permettent de mettre en avant les bonnes
pratiques de conception. Les Design Patterns étant largement documentés et connus d’un
grand nombre de développeurs ils permettent également de faciliter la communication. Si un
développeur annonce que sur ce point du projet il va utiliser le Design Pattern Observateur il
est compris des informaticiens sans pour autant rentrer dans les détails de la conception
(diagramme UML, objectif visé...).

4. Organisation des patrons de conception


Les patrons de conception sont classés en trois catégories :
 Création : ils permettent d’instancier et de configurer des classes et des objets.
 Structure : ils permettent d’organiser les classes d’une application.
 Comportement : ils permettent d'organiser les objets pour qu’ils collaborent entre eux.
Chap 5 : Les design Pattern pour le temps réel 29
Pattern en Exemples
Design pattern Observateur (observer)
Catégorie:Comportement Fréquence d'utilisation: Forte Difficulté: Facile

Description du problème
On trouve des classes possédant des attributs dont les valeurs changent régulièrement. De
plus, un certain nombre de classes doit être tenu informé de l’évolution de ces valeurs. Il n’est
pas rare d’être confronté à ce problème notamment en développant une classe métier et les
classes d’affichages correspondantes.

Afin d’illustrer ce problème récurent, prenons un exemple volontairement simpliste. On


considère une classe HeurePerso possédant dans le même attribut l’heure et la minute
courante. Cette classe, et plus particulièrement son attribut, est utilisé pour l’affichage de
l’heure courante dans une fenêtre, lors de l’écriture de logs... Pour cela, on définit une classe
AfficheHeure qui se charge d’afficher l’heure et la minute courante dans une partie de la
fenêtre. On peut alors se demander quelle démarche adopter pour que la classe chargée de
l’affichage soit tenue informée en temps réel de l’heure courante stockée dans la classe
HeurePerso ?

On peut identifier deux solutions. Soit la classe d’affichage se charge de demander à la classe
HeurePerso la valeur de son attribut soit c’est la classe HeurePerso qui informe la classe
AfficheHeure lors de changements.

Il est facile de s’apercevoir que la première solution n’est pas la meilleure. En effet, quand la
classe AfficheHeure devra t-elle questionner HeurePerso pour obtenir l’heure courante ?
Toutes les minutes ? Toutes les secondes ? Quelque soit l’intervalle choisi, soit l’heure ne sera
pas précise soit on surchargera d’appels inutiles la classe HeurePerso.

La solution consiste donc à laisser la charge à la classe HeurePerso d’informer sa classe


d’affichage de ses changements de valeurs. Cependant la classe HeurePerso doit pouvoir
informer plusieurs classes d’affichage et cela en évitant de lier fortement les classes entre
elles. C’est à dire qu’une modification des classes d’affichage ne doit pas engendrer de
modification dans la classe métier et vice versa. Comment peut-on faire ? Il est temps
d’étudier le diagramme UML du pattern Observateur qui répond de manière éprouvée à cette
problématique.

Chap 5 : Les design Pattern pour le temps réel 30


Diagramme UML

Définition de la solution
Le diagramme UML du pattern Observateur définit deux interfaces et deux classes. L’interface
Observateur sera implémenté par toutes classes qui souhaitent avoir le rôle d’observateur. C’est le
cas de la classe ObservateurConcret qui implémente la méthode actualiser(Observable). Cette
méthode sera appelée automatiquement lors d’un changement d’état de la classe observée.
On trouve également une interface Observable qui devra être implémentée par les classes
désireuses de posséder des observateurs. La classe ObservableConcret implémente cette interface,
ce qui lui permet de tenir informer ses observateurs. Celle-ci possède en attribut un état (ou
plusieurs) et un tableau d’observateurs. L’état est un attribut dont les observateurs désirent suivre
l’évolution de ses valeurs. Le tableau d’observateurs correspond à la liste des observateurs qui sont
à l’écoute. En effet, il ne suffit pas à une classe d’implémenter l’interface Observateur pour être à
l’écoute, il faut qu’elle s’abonne à un Observable via la méthode ajouterObservateur(Observateur).
En effet, la classe ObservableConcret dispose de quatre méthodes que sont
ajouterObservateur(Observateur), supprimerObservateur(Observateur), notifierObservateurs() et
getEtat(). Les deux premières permettent, respectivement, d’ajouter des observateurs à l’écoute
de la classe et d’en supprimer. En effet, le pattern Observateur permet de lier dynamiquement
(faire une liaison lors de l’exécution du programme par opposition à lier statiquement à la
compilation) des observables à des observateurs. La méthode notifierObservateurs() est appelée
lorsque l’état subit un changement de valeur. Celle-ci avertit tous les observateurs de cette mise à
jour. La méthode getEtat() est un simple accesseur en lecture pour l’état. En effet, les
observateurs récupèrent via la méthode actualiser(Observable) un pointeur vers l’objet observé.
Puis, grâce à ce pointeur, et à la méthode getEtat() il est possible d’obtenir la valeur de l’état.

Appliquons l’exemple précédent à ce diagramme UML. HeurePerso correspond à la classe

Chap 5 : Les design Pattern pour le temps réel 31


ObservableConret dont l’heure et la minute courantes seraient son état. La classe AfficheHeure
correspond elle à ObservateurConcret.

Approfondissement de la solution
Une des questions récurrente face à ce pattern est pourquoi ces deux interfaces ? D’ailleurs on
trouve sur Internet des implémentations de ce pattern sans ces deux interfaces... Mais l’utilisation
de ces interfaces permet de coupler faiblement l’observable à ses observateurs. En effet, un
principe de conception est de lier des interfaces plutôt que des classes afin de pouvoir faire évoluer
le modèle facilement. L’utilisation de ces deux interfaces n’est donc pas obligatoire mais elle est
vivement conseillée.

Cependant, il existe une variation possible lors de l’utilisation de ce pattern. Dans la solution
présentée ci dessous, une référence vers l’objet observable est mis à disposition de chaque
observateur. Ainsi les observateurs peuvent l’utiliser pour appeler la méthode getEtat() et ainsi
obtenir l’état de l’observable. Cette solution est nommée « TIRER » car c’est aux observateurs, une
fois avertis de l’évolution, d’aller chercher l’information sur l’état. Mais il existe la solution inverse
appelée « POUSSER ». Dans ce cas, on passe directement l’état actuel de l’observable dans la
méthode actualiser(TypeEtat). Ainsi les observateurs disposent directement de l’état. Mais
pourquoi avoir présenté la solution nommée « TIRER » plutôt que l’autre ? Parce qu’elle permet
une fois de plus de lier faiblement l’observable à ses observateurs. En effet, si l’observateur
dispose d’un pointeur vers l’objet observable et que la classe observable évolue en ajoutant un
deuxième état. L’observateur souhaitant se tenir informé de ce deuxième état aura juste à appeler
l’accesseur correspondant. Alors que si on « POUSSER » il faudrait changer la signature de la
méthode ce qui peut s’avérer plus dommageable.

Conséquences
Un exemple que l’on rencontre souvent pour illustrer ce pattern est une représentation entre une
entreprise qui diffuse un magazine et des personnes qui souhaitent s’y abonner (observateurs) et
donc le recevoir régulièrement.

Le pattern observateur permet de lier de façon dynamique un observable à des observateurs. Cette
solution est faiblement couplée ce qui lui permet d’évoluer facilement avec le modèle. D’ailleurs le
pattern Observateur est très utilisé. Il fait partie, par exemple, des patterns indispensables pour
mettre en place le modèle MVC (Modèle Vue Contrôleur) très en vogue actuellement.

 Exemples d'implémentations: 

Design pattern Observateur en Java : positionnement via un GPS

Design pattern Décorateur (decorator)


Catégorie:Structure

Chap 5 : Les design Pattern pour le temps réel 32


Fréquence d'utilisation:Normale Difficulté: Intermédiaire

Le pattern Décorateur (Decorator) attache dynamiquement des responsabilités


supplémentaires à un objet. Il fournit une alternative souple à l’héritage, pour étendre
des fonctionnalités.

Description du problème
Dans la programmation orientée objet, la façon la plus classique d’ajouter des fonctionnalités à une
classe est d’utiliser l’héritage. Pourtant il arrive parfois de vouloir ajouter des fonctionnalités à une
classe sans utiliser l’héritage. En effet, si l’on hérite d’une classe la redéfinition d’une méthode peut
entraîner l’ajout de nouveaux bugs. On peut aussi être reticent à l’idée que des méthodes de la
classe mère soient appelées directement depuis notre nouvelle classe.

De plus, l’héritage doit être utilisé avec parcimonie. Car si on abuse de ce principe de la
programmation orientée objet, on aboutit rapidement à un modèle complexe contenant un grand
nombre de classes.

Un autre souci de l’héritage est l’ajout de fonctionnalités de façon statique. En effet, l’héritage de
classe se définit lors de l’écriture du programme et ne peut être modifié après la compilation. Or,
dans certains cas, on peut vouloir rajouter des fonctionnalités de façon dynamique.

D’une manière générale on constate que l’ajout de fonctionnalités dans un programme s’avère
parfois délicat et complexe. Ce problème peut être résolu si le développeur a identifié, dès la
conception, qu’une partie de l’application serait sujette à de fortes évolutions. Il peut alors faciliter
ces modifications en utilisant le pattern Décorateur. La puissance de ce pattern qui permet
d’ajouter (ou modifier) des fonctionnalités facilement provient de la combinaison de l’héritage et de
la composition. Ainsi les problèmes cités ci-dessus ne se posent plus lors de l’utilisation de ce
pattern.

Diagramme UML

Chap 5 : Les design Pattern pour le temps réel 33


Définition de la solution
La classe abstraite Composant définit le point de départ de ce diagramme. Plusieurs
ComposantConcret peuvent hériter de Composant. Si l’on souhaite étendre (ou modifier)
l’ensemble des fonctionnalités des ComposantConcret on peut créer un décorateur. Il s’agit d’une
classe abstraite héritant de Composant et ayant un attribut de type Composant. De plus,
Decorateur déclare abstraite la méthode dont l’on souhaite étendre les fonctionnalités. Pour ajouter
des fonctionnalités à un ensemble de ComposantConcret on va créer des classes
DecorateurConcret qui héritent de Decorateur. Un DecorateurConcret contient un constructeur
permettant d’initialiser l’attribut composant présent dans le décorateur. Il faut ensuite que la classe
DecorateurConcret redéfinisse la méthode déclarée abstraite dans le décorateur. Lors de cette
redéfinition il est possible d’étendre les fonctionnalités en appelant la méthode de l’attribut
composant et en ajoutant des traitements.

Suivant les besoins spécifiques de chacun ce pattern peut être adapté. En effet, il est tout à fait
possible d’utiliser des interfaces pour le composant et le décorateur. Dans ce cas, les attributs et
les méthodes seront définis dans les sous classes.

Bien sûr ce pattern utilise largement l’héritage mais il utilise aussi la composition grâce à l’attribut
Composant présent dans le décorateur. C’est l’alliance de ces deux procédés qui permet à ce
pattern d’être si efficace.

Explication détaillée de la solution


Voyons plus concrètement comment fonctionne ce pattern en prenant un exemple de l’utilité de ce
pattern. Tout d’abord on a une classe ComposantConcret qui possède une méthode chargée d’une
fonctionnalité. Suivant l’objet créé on souhaite ajouter des traitements lors de l’appel de cette
méthode. Cependant on ne doit pas modifier directement le corps de la méthode car certains objets
utiliseront toujours l’ancienne version de cette méthode. Pour cela on peut créer un objet
DécorateurConcret en passant à son constructeur notre objet ComposantConcret (dont l’on
souhaite étendre les fonctionnalités). On peut ensuite redéfinir la méthode concernée et ajouter
des traitements. On appelle la méthode du ComposantConcret puis on rajoute des fonctionnalités.

On obtient un objet ComposantConcret qui est emballé dans un DecorateurConcret. Ainsi si on


appelle la méthode sur l’objet décorateur, celle-ci va appeler la méthode du composant concret,
ajouter ses propres traitements et retourner le résultat. A noter, que si on appelle directement la
méthode de l’objet ComposantConcret (sans passer par le décorateur) on utilise alors l’ancienne
version de la méthode.

Conséquences
Comme tous les patrons de conception, Décorateur ne doit pas être utilisé à tord et à travers. Mais
lors de la conception de classes qui risquent d’évoluer fortement (ajout ou modification de
fonctionnalités) celui-ci sera très utile. Il est donc important de bien réfléchir aux points sensibles
de l’application qui risquent d’évoluer au fil du temps et cela dès la phase d’analyse.

Attention tout de même à l’utilisation des types concrets. Si votre application se base sur les types
concrets d’objets utilisés dans le pattern décorateur cela posera des problèmes. En effet, une fois

Chap 5 : Les design Pattern pour le temps réel 34


décoré un ComposantConcret aura pour type concret celui de son décorateur le plus externe.

De plus, lors de l’utilisation du pattern Décorateur, on constate qu’il est fastidieux de gérer tous les
objets créés et de les décorer. C’est pour cette raison que ce pattern est souvent utilisé avec le
pattern Fabrique ou Monteur qui répondent à cette problématique.

Exemples d'implémentations: 

Design pattern Décorateur en Java : vente de desserts

Design pattern Fabrique (Factory Method)


Soumis par Mathieu G. le Jeudi 17/11/2011 21:08 - Dernière modification le Jeudi 09/05/2013 20:21

Catégorie: Création Fréquence d'utilisation: Forte Difficulté: Intermédiaire

Le design pattern Fabrique (Factory Method) définit une interface pour la création d'un
objet en déléguant à ses sous-classes le choix des classes à instancier.

Description du problème
Il est fréquent de devoir concevoir une classe qui va instancier différents types d'objets suivant un
paramètre fourni. Par exemple une usine va fabriquer des produits en fonction du modèle qu'on lui
indique.
L'idée la plus simple pour répondre à ce besoin est d'écrire une succession de conditions qui
suivant le modèle demandé, instancie et retourne l'objet correspondant.

Le problème avec cette implémentation, c'est que la classe correspondant à l'usine va être
fortement couplée à tous les produits qu'elle peut instancier car elle fait appel à leur type concret.
Or ce code va être amené à évoluer régulièrement lors de l'ajout de nouveaux produits à fabriquer
ou de la suppression de certains produits obsolètes.

De plus, il est fort probable que l'instanciation des différents produits soit également réalisée dans
d'autres classes par exemple pour présenter un catalogue des produits fabriqués.

On se retrouve alors avec du code fortement couplé, qui risque d'être dupliqué à plusieurs endroits
de l'application.

Début de solution
La première solution est de regrouper l'instanciation de tous les produits dans une seule classe
chargée uniquement de ce rôle. On évite alors la duplication de code et on facilite l'évolution au
niveau de la gamme des produits.

Cette solution appelée Fabrique Simple est une bonne pratique de conception mais pas un design
pattern. En effet, le design pattern Fabrique est plus évolué et offre plus de flexibilité, donc
attention à ne pas les confondre. Pour autant cette bonne pratique est régulièrement utilisée et
s'avère efficace dans les cas les plus simples (voir son diagramme UML ci-dessous).

Chap 5 : Les design Pattern pour le temps réel 35


L'utilisateur du produit fait appel à la Fabrique Simple pour obtenir un Produit. C'est la Fabrique
Simple qui est chargée d'instancier et de retourner le Produit Concret attendu (par exemple grâce à
un paramètre passé en argument de la fonction). L'utilisateur du produit est donc fortement couplé
uniquement à la Fabrique Simple et non à tous les produits qu'il prend en charge.

Si par la suite l'entreprise évolue et a besoin de plusieurs usines, chacune spécialisée dans la
fabrication de certains produits, Fabrique Simple ne va plus suffire.
Dans ce cas il faut prévoir l'utilisation du design pattern Fabrique dont le diagramme UML est
présenté ci-dessous.

Diagramme UML

Définition de la solution
Le créateur contient toutes les méthodes permettant de manipuler les produits exceptée la
méthode creerProduit qui est abstraite. Les créateurs concrets implémentent la méthode
creerProduit qui instancie et retourne les produits. Chaque créateur concret peut donc créer des
produits dont il a la responsabilité. Pour finir tous les produits implémentent la même interface afin
que les classes utilisant les produits (comme le créateur) puissent s'y référer sans connaître les
types concrets.

Si une partie de l'implémentation est identique à tous les produits concrets, alors l'interface Produit
peut être une classe abstraite afin d'intégrer ce code partagé dans celle-ci. Il est également
bénéfique d'utiliser ce pattern même si l'on a qu'un seul CreateurConcret ou qu'un CreateurConcret
n'instancie qu'un seul Produit car les avantages liés au découplage des produits et du créateurs
sont conservés.

A noter que les créateurs concrets utilisent la bonne pratique Fabrique Simple présentée
précédemment. Mais comparé à cette bonne pratique qui ne sert qu'une fois, le design pattern
Fabrique permet de créer une structure où l'ajout d'une sous classe (c'est à dire un créateur
concret) permet de choisir les produits qui seront utilisés. C'est d'ailleurs ce qui explique la
définition de ce pattern.

Chap 5 : Les design Pattern pour le temps réel 36


Conséquences
Le pattern Fabrique doit être utilisé pour découpler les clients des classes concrètes à instancier, ou
si l'on ne connaît pas d'avance toutes les classes concrètes à instancier.

Pour créer des familles de produits cohérentes, on sera amené à utiliser le design pattern Fabrique
Abstraite qui répond spécifiquement à ce besoin.

Exemples d'implémentations: 

Design pattern Fabrique (Factory Method) en Java  : jeu de stratégie

Chap 5 : Les design Pattern pour le temps réel 37

Vous aimerez peut-être aussi