Académique Documents
Professionnel Documents
Culture Documents
Post-graduation
Reconnaissance des Formes & Intelligence Artificielle.
Exposé :
Module : Parallélisme.
Responsable : M. BELKADI.
Septembre 2003
Langages de Programmation Parallèle, Java & Simula.
Sommaire
SOMMAIRE.......................................................................................................................................1
INTRODUCTION..............................................................................................................................2
PARTIE I : JAVA ..............................................................................................................................3
1- INTRODUCTION .............................................................................................................................3
2- CONCEPTS ET NOTIONS DE BASE....................................................................................................3
3- APPLETS ET PROGRAMMES JAVA ...................................................................................................9
4. LES FICHIERS ...............................................................................................................................13
5. JAVA EN RESEAU .........................................................................................................................15
6. PARALLELISME SOUS JAVA..........................................................................................................18
PARTIE II : SIMULA .....................................................................................................................28
1- INTRODUCTION ...........................................................................................................................28
2. DESCRIPTION GENERALE .............................................................................................................28
3. CALCUL ARITHMETIQUE ..............................................................................................................30
4. AUTRES DECLARATIONS ..............................................................................................................33
5. PROCEDURES ...............................................................................................................................35
6. ASPECTS AVANCES ......................................................................................................................36
7. ASPECT PARALLELE.....................................................................................................................40
CONCLUSION ................................................................................................................................43
BIBLIOGRAPHIE...........................................................................................................................43
1
Langages de Programmation Parallèle, Java & Simula.
Introduction
Il est assez clair aujourd’hui que la maîtrise de la construction et de l’évolutivité d’un grand système
réparti passe par l’adoption d’un processus de conception unifié, permettant de traverser en douceur
les différentes phases du cycle de développement. Les langages de programmation orientés-objets
(LOO) ne constituent qu’un outil hôte de codage que l’on doit bien maîtriser avant de pouvoir
efficacement l’utiliser. Certes ces langages sans très bien adaptés à la programmation parallèle,
reste à maîtriser tout le processus de développement d’un produit utile, efficace et réutilisable.
Pour relever le défi d’un développement continuellement validé des systèmes répartis ouverts
fabriqués à base d’objets, il faut particulièrement soigner :
• la prise en compte correcte du parallélisme et de la répartition dans une approche objets, sans
trop nuire aux performances des implantations,
• la disponibilité d’outils de validation dans toutes les phases du cycle de développement.
Dans la perspective de maîtriser les outils de « parallélisation » offerts par les LOO, nous
présentons dans cet exposé deux langages repères dans le domaine. Simula, l’ancêtre des LOO, et
l’un de ses derniers petits-fils, Java.
Nous consacrons pour chacun des deux une partie séparée présentant les concepts de base, quelques
aspects avancés, plusieurs exemples, mais surtout le mécanisme et les outils de parallélisation.
2
Langages de Programmation Parallèle, Java & Simula.
Partie I : JAVA
1- Introduction
Les grandes sociétés, ont adopté Java bien plus intensément qu’on le pense. Chez IBM, la moitié
des salariés s’emploient à recoder en Java des milliards de lignes de programmes. L’autre moitié
s’efforce de faire efficacement tourner Java sur toutes les plates-formes [4].
Le langage de programmation Java a été développé en décembre 1990 par « Sun Microsystems »
dans le cadre du projet « Green ». Les chercheurs –spécialisés dans l’électronique grand public-
travaillaient sur un langage de programmation, qui permettrait aux futurs ustensiles domestiques de
communiquer entre eux. L’idée de départ était de développer le système d’exploitation Star7 en
C++, mais James Gosling, membre du projet Green, fut vite lassé du peu d’efficacité de C++ pour
cette tâche précise ; enfermé dans son bureau, il écrivit alors un nouveau langage permettant de
mieux gérer le Star7.
Java n’étant pas retenu comme outils de développement pour ustensiles, l’avenir du projet Green
sembla donc compromis. C’est alors que le World Wide Web prit son essor.
Vu ses caractéristiques applicables au Web (non encombrant, portable, sécurisé), Java a été
considéré comme un jouet créatif pour les utilisateurs du Web, lors de sa mise en service en 1995
par Sun Microsystems [4].
Les langages de programmation sont en général interprétés (Basic ou JavaScript) ou compilés
(Pascal ou C). Pour pouvoir être un langage multi-plateforme, Java est un mélange de ces deux
possibilités : les fichiers sources .java doivent être compilés pour fournir un fichier .class qui pourra
lui, être interprété. Programmer en java suppose donc que l'on dispose d'un compilateur et d'un
interpréteur java. Ceux-ci sont fournis par le JDK (Kit de Développement en Java) disponible
gratuitement sur le site de la société SUN [2][4].
2- Concepts et notions de base
Lire et apprendre toute la syntaxe d’un langage avant de passer à des pratiques pilotes est une
approche peu rentable pour découvrir et maîtriser un langage. Un programmeur « assoiffé » de
codage préfère apprendre quelques concepts et pratiquer de petits programmes afin de chercher
toute la fermeture syntaxique du langage. Java puise l’essentiel de sa syntaxe du langage C ou
mieux encore C++, il exploite largement les concepts orientés-objets.
2.1. Syntaxe générale
Sans nous bloquer dans une labyrinthe syntaxique, nous donnons brièvement la syntaxe globale
d’une déclaration d’une classe Java. Les autres règles syntaxiques seront découvertes
progressivement à travers la panoplie d’exemples présentés par la suite.
class_declaration
::=
{ modifier } "class" identifier
[ "extends" class_name ]
[ "implements" interface_name { "," interface_name } ]
"{" { field_declaration } "}"
3
Langages de Programmation Parallèle, Java & Simula.
La déclaration d'une interface est similaire à la déclaration d'une classe, sauf que l'on ne fait que
déclarer les méthodes, sans les remplir.
volatile précise que la variable peut être changée par un périphérique ou de manière asynchrone. Cela indique au compilateur
qu'il ne doit pas stocker les valeurs dans des registres. A chaque utilisation, on lit la valeur, et on réécrit immédiatement le
résultat s'il a changé.
abstract
Le modificateur abstract indique que la classe auquel on l'ajoute est une classe qui ne pourra pas etre instanciée telle quelle.
De plus, toutes les méthodes déclarées abstract dans cette classe ne sont pas implémentées et devront être remplacées par
des méthodes complètes dans ses sous-classes.
transient
Ce mot clé a été réservé par Sun, et ne doit pas être utilisé comme identificateur. Il sera vraisemblablement utilisé par le futur
système de distribution d'objet. La page http://www.javasoft.com/ vous tiendra au courant des nouveaux développements.
Crayon
class Crayon {
protected int longueur = 100; // en millimetres
protected int diametre = 5; // en millimetres
5
Langages de Programmation Parallèle, Java & Simula.
// cree un crayon de longueur l et de diametre d
public Crayon(int l,int d) {
longueur = l;
diametre = d;
}
}
CrayonCouleur
class CrayonCouleur extends Crayon {
public CrayonCouleur() {
super();
}
public CrayonCouleur(String c) {
super();
couleur = c;
}
6
Langages de Programmation Parallèle, Java & Simula.
...
int entA = 1,entB = 2,entC = 9;
float fA = 1.3,fB = 2.6;
2.5. Interfaces
Une interface est un modèle d'implémentation. Tous les objets qui implémentent une interface
possèdent les méthodes déclarées dans celle-ci. On utilise souvent les interfaces dans les types de
paramètres. En effet, dans certains cas, peu importe la classe d'un objet donné, car cela ne nous
intéresse pas. Nous avons seulement besoin de savoir que telle ou telle classe possède ces méthodes
et se comporte de telle manière.
On peut imaginer une interface appareilElectrique qui définit les méthodes estEnclenche() et
alimente(boolean). Si une classe implémente l'interface appareilElectrique, on sait donc qu'elle possède au
moins ces deux méthodes, qu'il s'agisse d'une radio, d'une lampe ou d'un autre appareil. Lorsque l'on
désire indiquer à un appareil qu'il est alimenté, on exécute app.alimente(true), et pour lui indiquer qu'il
a été débranché, on exécute app.alimente(false).
Nous allons donc créer deux types d'appareils électriques, les radios et les lampes. Ces deux types
implémentent l'interface appareilElectrique. Nous allons également créer une classe rallongeElectrique,
qui est aussi un appareil électrique. La méthode la plus intéressante de cette classe est la méthode
branche(appareilElectrique). Celle-ci enregistre l'objet fourni en paramètre comme étant l'objet alimenté
à travers la rallonge. Cette rallonge possède un interrupteur, que l'on peut activer ou désactiver en
appelant ses méthodes enclenche(), respectivement declenche(). Lorsque l'on change l'état de
l'interrupteur, on indiquera à l'objet qui en dépend qu'il est ou qu'il n'est plus alimenté. La page
"déclaration d'interface" peut également intéresser le lecteur.
Interface - appareilElectrique
public interface appareilElectrique {
}
Implémentation - radio
// c'est une radio rudimentaire, qui se deregle quand on l'eteint !
7
Langages de Programmation Parallèle, Java & Simula.
freq = freqMiseEnRoute;
}
}
Implémentation - lampe
class lampe implements appareilElectrique {
}
Implémentation - rallongeElectrique
class rallongeElectrique implements appareilElectrique {
/* gestion de l'interrupteur
*/
public void enclenche() {
if (!conduit && estAlimente)
on();
conduit = true;
}
8
Langages de Programmation Parallèle, Java & Simula.
appareilBranche.alimente(true);
}
}
Exemple d'utilisation - testElectrique
class testElectrique {
}
Exécution
la radio du salon est eteinte
on appuie sur l'interrupteur de la rallonge 1
la radio du salon est maintenant allumee
9
Langages de Programmation Parallèle, Java & Simula.
Exemple
class exSimple1 {
public static void main(String args[]) {
int entA = 10;
int entB = 12;
int entX;
System.out.println("comptons de 1 a "+entA);
int somme = 0;
int fact = 1;
for (int i = 1;i <= entA;i++) {
System.out.print(" "+i);
somme += i;
fact *= i;
}
System.out.println();
System.out.println("la somme de tous les nombres de 1 a "+entA+" vaut
"+somme);
System.out.println("la factorielle de "+entA+" vaut "+fact);
}
}
Exécution
L'entier A vaut 10
L'entier B vaut 12
A est plus petit que B
comptons de 1 a 10
1 2 3 4 5 6 7 8 9 10
la somme de tous les nombres de 1 a 10 vaut 55
la factorielle de 10 vaut 3628800
10
Langages de Programmation Parallèle, Java & Simula.
Mise en oeuvre
Tout programme Java est une classe. Une applet n'échappe pas à cette règle. Si l'on veut créer une
applet, on doit étendre la classe java.applet.Applet. Cette classe contient les méthodes nécessaires à la
gestion de l'applet, et à l'interaction de celle-ci avec son environnement (browser).
Voyons les méthodes les plus importantes, que votre applet devra remplacer si nécessaire :
public void init()
Le browser fait appel à cette méthode lorsque l'applet est chargée (ou rechargée). Cette
méthode devra charger les informations telles que images ou sons, et récupérer les
paramètres présents dans la page HTML.
public void start()
Après avoir été initialisée, l'applet est démarrée, grâce à la méthode start(). L'applet est
également redémarrée après avoir été stoppée, lorsqu'elle est à nouveau visible.
public void stop()
Cette méthode permet à l'applet de s'arrêter lorsqu'elle n'est plus visible, parce que
l'utilisateur a changé de page, par exemple.
public void destroy()
L'applet est détruite lorsque le browser s'arrête, ou avant que l'applet soit rechargée. Cette
méthode doit être remplacée si l’on veut stopper des threads créés par start() de l'applet.
public void paint(Graphics g)
Cette méthode est appelée chaque fois que l'on doit redessiner l'applet. Le paramètre est de
type Graphics et c'est la surface de dessin sur laquelle on doit travailler.
Exemple
import java.awt.*;
import java.applet.*;
Font font;
Cette applet n'implémente pas la méthode start(), car aucune tâche n'est effectuée en permanence. La
seule chose que l'applet fait est de se redessiner lorsque le browser le redemande
(paint(Graphics g)).
Que se passe-t-il si l'on veut que l'applet ait une activité permanente ? Toutes les applets s'exécutant
dans browser utilisent la même machine virtuelle Java. On ne peut donc pas créer une boucle dans
la méthode start() pour effectuer une tâche, parce que l'on occuperait la MV (machine virtuelle). Il
faut donc créer un thread afin d'autoriser l'exécution parallèle des multiples applets.
Exemple
import java.awt.*;
Thread tache;
String lbl;
Font font;
boolean gris = false;
11
Langages de Programmation Parallèle, Java & Simula.
}
Lorsque l'utilisateur agit sur un objet graphique tel que bouton ou champ de texte, le logiciel de
navigation envoie des actions et des événements au panneau contenant l'objet. Les actions sont
similaires aux événements, sauf qu'ils ne sont pas traités par la méthode handleEvent, mais action.
Chaque panneau possède sa propre méthode action. Si l'on ne remplace pas cette méthode par une
méthode spécifique, l'événement (action) se propagera automatiquement au panneau parent, et ainsi
de suite.
4. Les fichiers
En Java, on peut facilement accéder à des fichiers à partir d'une application. On ne peut pas le faire
à partir d'une applet pour des questions de sécurité. On remarquera également qu'à tout accès au
système de fichiers, il peut se produire une exception java.io.IOException.
L'exemple ci-dessous montre comment obtenir des informations sur un fichier. Notons qu'il n'existe
pas de classe spéciale pour traiter des répertoires, ceux-ci sont considérés comme des fichiers.
4.1. Informations sur un fichier
import java.io.*;
class fileInfo {
public static void main (String args[]) throws java.io.IOException {
System.out.println("Entrez le repertoire ou se trouve le fichier : ");
char ch;
// directory
13
Langages de Programmation Parallèle, Java & Simula.
StringBuffer dirBuf = new StringBuffer();
while ((ch = (char)System.in.read()) != '\n')
dirBuf.append(ch);
File dir = new File(dirBuf.toString());
// file
System.out.println("Entrez le nom du fichier : ");
StringBuffer fileBuf = new StringBuffer();
while ((ch = (char)System.in.read()) != '\n')
fileBuf.append(ch);
File fil = new File(dir,fileBuf.toString());
if (fil.exists()) {
System.out.println("Fichier trouve");
System.out.println("Nom de fichier : "+fil.getName());
System.out.println("Chemin du fichier : "+fil.getPath());
System.out.println("Chemin absolu : "+fil.getAbsolutePath());
System.out.println("Droit de lecture : "+fil.canRead());
System.out.println("Droit d'ecriture : "+fil.canWrite());
System.out.println("\nContenu du repertoire :");
String listing[] = dir.list();
for (int i = 0;i < listing.length;i++)
System.out.println(listing[i]);
} else {
System.out.println("Fichier absent");
}
}
}
import java.io.*;
class fileCopy {
public static void main (String args[]) throws java.io.IOException {
char ch;
// repertoire source
if (!srcDir.exists()) {
System.out.println("repertoire absent");
System.exit(1);
} else if (!srcDir.canRead()) {
System.out.println("repertoire illisible");
System.exit(1);
}
// fichier source
if (!srcFile.exists()) {
System.out.println("fichier absent");
System.exit(1);
} else if (!srcFile.canRead()) {
System.out.println("fichier illisible");
14
Langages de Programmation Parallèle, Java & Simula.
System.exit(1);
}
// repertoire destination
if (!dstDir.exists()) {
System.out.println("repertoire absent");
System.exit(1);
} else if (!dstDir.canWrite()) {
System.out.println("repertoire protege en ecriture");
System.exit(1);
}
// fichier destination
if (dstFile.exists()) {
System.out.println("fichier existant");
System.exit(1);
}
// copie du fichier
5. Java en réseau
On ne peut pas parler du langage Java sans présenter son aspect « réseautique ». En effet Java
s’appuie dans sa gestion des connexions réseaux sur des classes spécifiques qui gèrent les différents
ports TCP/IP et modélisent l’architecture client-serveur.
5.1. Les connexions réseau TCP/IP - la classe Socket
Avec Java, il est très facile d'ouvrir une connexion TCP/IP depuis une applet ou une application. La
classe Socket fournit tous les outils nécessaires à cela. Une fois qu'une connexion est réalisée avec
une autre machine, on a accès à un flux d'entrée et un flux de sortie, comme si l'on travaillait avec
un fichier.
Exemple
import java.io.*;
import java.net.*;
Serveur d'heure
import java.net.*;
import java.io.*;
import java.util.Date;
class serveurHeure {
16
Langages de Programmation Parallèle, Java & Simula.
Pour se connecter à ce serveur, on peut utiliser telnet ou l'utilitaire jnetcat qui a été décrit
précédemment. Le client qui se connecte sur le port 11111 du serveur peut voir apparaître un
message du type :
Bienvenue eig. Il est actuellement Thu May 30 14:12:35 MET DST 1996
Généralement, on désire pouvoir servir plusieurs applications clientes à partir du même serveur,
comme c'est le cas pour FTP et HTTP. Nous allons voir comment implémenter un serveur multi-
thread, qui crée un processus par client. Nous déclarons une classe connexion qui est capable de
traiter les entrées/sorties d'un client que nous instancions chaque fois qu'un client se connecte sur le
port serveur.
Le programme ci-dessous est un exemple de serveur qui peut s'accommoder de plusieurs clients
concurremment. Lorsqu'un client s'y connecte, le serveur initialise un compteur à 0, et chaque
nombre que le client lui envoie est additionné à ce compteur.
Serveur multi-clients
/* Serveur multi-clients
* Additionne tous les nombres fournis par les clients
*/
import java.io.*;
import java.net.*;
Socket client;
DataInputStream depuisClient;
PrintStream versClient;
int somme = 0;
try {
// creation des flux de/vers le client
depuisClient = new DataInputStream(client.getInputStream());
versClient = new PrintStream(client.getOutputStream());
17
Langages de Programmation Parallèle, Java & Simula.
// message d'accueil
versClient.println("Bienvenue sur le serveur additionneur");
versClient.println("Entrez un nombre suivi de entree");
} catch (IOException e) {
try { client.close(); } catch (IOException ee) {}
}
new Thread(this).start();
}
18
Langages de Programmation Parallèle, Java & Simula.
class thread12 {
thread1.start();
thread2.start();
while (true) {
System.out.println("je suis la tache principale !");
Thread.yield();
}
}
}
Exécution
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
Le problème est que la méthode Thread.stop() est qualifiée de final. On ne peut donc pas la remplacer.
Une autre solution est possible. L'interface Runnable permet de créer un objet, que l'on utilisera
ensuite comme constructeur d'un Thread. C'est la méthode start() de l'objet qui sera responsable de la
création et de l'activation du thread.
Exemple
class afficheurRunnable implements Runnable {
class runnable12 {
run1.start();
run2.start();
while (true) {
System.out.println("je suis la tache principale !");
try {
Thread.sleep(20);
} catch (InterruptedException e) {}
}
}
}
Exécution
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis le processus 1
je suis le processus 2
je suis le processus 1
je suis le processus 2
je suis le processus 1
je suis le processus 2
je suis la tache principale !
je suis le processus 1
je suis le processus 2
je suis le processus 1
je suis le processus 2
je suis le processus 1
Attention !
L'implémentation et le comportement de l'Ordonnanceur de processus (scheduler) n'est pas spécifié
par Sun. Cela veut dire que les différentes machines virtuelles (MV) Java n'auront pas forcément le
même comportement. Une MV peut se comporter comme un noyau temps réel (pas de timeslicing)
ou comme un noyau préemptif.
20
Langages de Programmation Parallèle, Java & Simula.
Comme nous l'avons vu dans les exemples précédents, on utilise Thread.yield() afin de redonner le
contrôle à l'ordonnanceur. De cette manière, quel que soit le comportement de la machine virtuelle
Java, les différents processus s'entrelaceront.
Il est également important de s'assurer que les accès concurrents aux variables et méthodes ne
mettent pas en péril la validité des données. Pour ce faire, veuillez vous reporter à la page décrivant
les mécanismes d'exclusion mutuelle de Java.
6.2. Exclusion mutuelle
Le mécanisme d'exclusion mutuelle présent dans Java est le moniteur. Si l'on désire définir une
section critique, afin de s'assurer de la cohérence des données, nous devons utiliser le mot-clé
synchronized. C'est de cette manière que l'on crée un moniteur.
Lorsque l'on crée une instance d'une certaine classe, on crée également un moniteur qui lui est
associé. Lorsque l'on applique le modificateur synchronized, on place la méthode (le bloc de code)
dans ce moniteur, ce qui assure l'exclusion mutuelle.
Exemple
class mutexAcc {
int accumulateur = 0;
L'utilisation de méthodes synchronisées trop longues peut créer une baisse d'efficacité. Avec Java,
il est possible de placer n'importe quel bloc dans un moniteur, ce qui permet ainsi de réduire la
longueur des sections critiques. Dans l'exemple suivant, le code de methode1 et de methode2 est
équivalent.
synchronized void methode1() {
// section critique...
}
void methode2() {
synchronized(this) {
// section critique...
}
}
Exemple
public class Tortue {
21
Langages de Programmation Parallèle, Java & Simula.
pos.y += (int) ((double)distance*Math.sin((double)angle));
}
Considérons maintenant le cas où il faut sécuriser l'accès à une variable de classe. La solution est
simple, il faut créer un moniteur qui est commun à toutes les instances de la classe. La méthode
getClass() retourne la classe de l'instance dans laquelle on l'appelle. Nous pouvons maintenant créer
un moniteur qui utilise le résultat de getClass() comme "verrou".
class mutexStatic {
private int accumulateur = 0;
private static int acces = 0;
22
Langages de Programmation Parallèle, Java & Simula.
}
}
Cet exemple définit une classe d'accumulateur qui incrémente acces chaque fois que l'on accède à
stocke ou à lit. La variable acces est une variable de classe (déclarée public), elle est donc partagée par
les différentes instances de cette classe. La méthode getClass() retourne un objet de type Class avec
lequel on crée un nouveau moniteur.
6.3. Synchronisation : les méthodes wait() et notify()
Il peut être nécessaire de synchroniser des processus qui accèdent aux mêmes ressources.
L'utilisation des moniteurs permet de garantir l'exclusion mutuelle, et pour la synchronisation, on
utilisera des signaux, qui sont modélisés par les méthodes wait() et notify().
Un des exemples classiques de l'utilisation des signaux est celui des producteurs-consommateurs.
Prenons un tampon borné de n objets, un processus producteur et un processus consommateur.
Exemple - tamponCirc.java
class tamponCirc {
private Object tampon[];
private int taille;
private int en, hors, nMess;
class utiliseTampon {
prod.start();
cons.start();
try {
Thread.sleep(30000); // s'execute pendant 30 secondes
} catch (InterruptedException e) {}
}
}
Exécution
...
je depose 165
je depose 166
je preleve 161
je depose 167
je preleve 162
je depose 168
je preleve 163
je depose 169
je preleve 164
je depose 170
je preleve 165
je depose 171
je preleve 166
je preleve 167
...
Nous déclarons 2 processus, un producteur et un consommateur. Les données sont produites plus vite
que le consommateur ne peut les prélever, à cause de la différence de durée des délais (aléatoires)
introduits dans les 2 processus.
Il existe deux variantes de la méthode wait() qui permettent de spécifier un temps limite après lequel
le processus sera réveillé, sans avoir à être notifié par un processus concurrent. Il s'agit de wait(long
milli), qui attend milli millisecondes, et de wait(long milli,int nano) qui attend nano nanosecondes en
24
Langages de Programmation Parallèle, Java & Simula.
plus du temps milli. Il n'est pas possible de savoir si wait() s'est terminé à cause d'un appel à notify()
par un autre processus, ou de l'épuisement du temps.
La méthode notifyAll() réveille tous les processus, et dès que le moniteur sera libre, ils se réveilleront
tour à tour.
Attention !
Le noyau Java ne fait aucune garantie concernant l'élection des processus lors d'un appel à notify().
En particulier, il ne garantit pas que les processus seront débloqués dans l'ordre ou ils ont été
bloqués. C'est à cause de cela que l'on a placé wait() dans une boucle dans l'exemple précédent, car
un consommateur pourrait réveiller un autre consommateur alors que le tampon est vide.
Remarquons aussi que les méthodes wait, notify() et notifyAll() ne peuvent être appelées que dans des
méthodes synchronisées (synchronized).
6.4. L’interface Runnable
Les applets peuvent utiliser des processus en implémentant l'interface Runnable qui demande une
méthode run. Le processus doit être associé à l'applet par son constructeur, sa méthode start appelle
alors la méthode run de l'applet [3].
Squelette d'applet implémentant l'interface Runnable
L'applet gère un processus à travers une variable de type Thread. Sa méthode start, appelée juste
après init, crée le processus et le démarre, ce qui provoque l'exécution de la méthode run. Celle-ci
est formée d'une boucle dans laquelle se fait le travail du processus, avec à chaque tour un arrêt
(méthode wait) permettant au processus principal de l'applet de s'exécuter pour la gestion des
évènements (affichage, souris, boutons, etc...). Une variable speed permet de gérer le temps d'arrêt
qui est exprimé en millièmes de secondes. Enfin nous utilisons la méthode stop de l'applet, qui est
appelée lors de la fermeture de la page html, pour stopper le processus.
import java.awt.*;
import java.applet.*;
25
Langages de Programmation Parallèle, Java & Simula.
import java.awt.*;
import java.applet.*;
26
Langages de Programmation Parallèle, Java & Simula.
En utilisant le modèle fourni précédemment, il nous a suffi d'écrire les méthodes init (choix des
couleurs) et paint (affichage), puis de compléter la méthode run pour incrémenter le nombre de
secondes [3].
27
Langages de Programmation Parallèle, Java & Simula.
Partie II : SIMULA
1- Introduction
SIMULA est le premier langage orienté-objet conçu initialement pour créer des environnements de
simulation assez puissant pour modéliser des problèmes réels (système de production, simulation et
conception assistée par ordinateur, …)
En effet, SIMULA a été le premier langage à utiliser le concept d'OBJET; et ce depuis 1967. Le
concept a ensuite été repris pour la programmation graphique interactive par Smalltalk. Ce qui a
vraiment lancé la programmation objet sur le marche nord-américain, c'est C++, un C amélioré
conçu par B.Stroustrup, un fan de Simula qui voulait faire de la simulation dans l'environnement C
de Bell_Labs. Et donc, 20 ans après son invention par Dahl et Nygaard [1], la programmation objet
a été redécouverte par le reste du monde. La référence de base reste la norme du « Swedish
Standards Institute ».
Simula67 était à peu de choses près identique au Simula d'aujourd'hui - le standard a été mis à jour
en 1987 - et c'était le premier langage orienté-objet. Conçu pour décrire (et programmer) des
systèmes complexes comportant des activités parallèles, Simula67 est basé sur le concept de Class
(type abstrait) décrivant les attributs et méthodes d'un ensemble d'objets. L'héritage simple entre
classes est exprimé en préfixant la définition d'une sous-classe par le nom de sa sur-classe [5].
Nous présentons dans cette partie les notions de base du langage Simula, les structure et la syntaxe
la plus utilisée, et surtout son aspect de simulation et de parallélisme [5].
2. Description générale
Voici un programme complet qui montre l'allure de SIMULA . Ceci nous permettra de faire
quelques commentaires généraux.
begin
! programme simple ;
integer i,j;
integer carre ;
i:= inint; j:= inint;
carre := i*i;
outtext(" i carre somme"); outimage;
outint(i,5);
outint(carre,5);
outint(i+j, 6);
outimage;
end
On peut aussi déclarer des constantes en ajoutant une valeur dans la déclaration:
Simula Pascal
const
nMax = 100; integer nMax = 100;
Pi = 3.1416; real Pi = 3.1416;
1. vérifier le sens des opérations (p.e. empêcher l'addition d'un texte et d'un booléen)
2. réserver des zones de mémoire pour stocker les informations
2.2. Entrée/Sorties
Les entrées/sorties sont en format libre et portent sur les entiers, réels, caractères et chaînes. Pour
chaque type on a une fonction pour l'entrée et une procédure pour la sortie qui transfèrent une
valeur à la fois. Pour les écritures, on doit spécifier la taille des champs.
Lecture Impression
Integer I:= inint ; outint(I,10) ;
Real X:= inreal ; outreal(X,2,10);
Character C:= inchar ; outchar( C ) ;
Text T:= intext(20) ; outtext(" OK !") ;
Entrées/Sorties en Simula
Autres opérations
Pascal Simula
read(I,R,C); I:= inint;
R:= inreal;
C:= inchar;
29
Langages de Programmation Parallèle, Java & Simula.
writeln(I,R:10:2,C,'OK'); outint(I,5);
outreal(R,2,10); ...gare à l'ordre
outchar(C);
outtext("OK");
outimage;
3. Calcul arithmétique
Les calculs se font par des énoncés d'affectations de la forme suivante:
variable := expression
Cet énoncé veut dire qu'on calcule d'abord la valeur de l'expression; puis on stocke cette valeur dans
la variable. Par exemple:
y := x + 1
veut dire: ajouter 1 à la valeur de x et mettre le résultat dans la variable y. Si x valait 4, alors, après
cet énoncé, y vaudra 5. Dans le cas d'expressions de valeurs numériques, les variables ( x et y dans
l'exemple) doivent être de type integer ou real.
Notez que les caractères de l'opérateur d'affection, ":=", doivent être collés côte à côte et la combinaison ":=" compte comme
un seul symbole en Simula.
3.1. Opérateurs
Dans les expressions arithmétiques, les opérateurs sont sensiblement les mêmes qu'en
mathématiques:
addition: "+"
soustraction: "-"
multiplication: "*"
division réelle: "/"
division entière: "//" ( et la fraction est tronquée )
exponentiation: "**" X ** i veut dire X à la puissance i
Ici encore les caractères des opérateurs composés, "//" et "**", doivent être côte à côte.
Remarquez que la multiplication, qui est souvent implicite en notation mathématique, doit être
notée explicitement. Donc l'expression mathématique (4a + b)(3c + d) devra être écrite comme suit
en Simula:
(4 * a + b) * ( 3 * c + d )
En Simula, il y a deux opérateurs de division, "/" et "//". L'opérateur "/" dénote la division usuelle et
le résultat est toujours de type real:
4 / 3 donne 1.333333...
et 4 / 2 donne 2.0
L'opérateur "//" dénote la division entière. Les opérandes doivent être de type integer et le résultat
sera un integer. Si résultat exact de la division comporte une fraction, celle-ci est ignorée. Donc,
4 // 2 donne 2
11 // 3 donne 3
-7 // 3 donne -2
7 // -3 donne -2
5 // 1.3 donne ERREUR car 1.3 n'est pas un entier
On peut récupérer le reste de la division de p // q avec la fonction rem(p, q). Reprenant les mêmes
exemples de division:
rem( 4,2 ) donne 0
rem(11,3 ) donne 2
rem(-7,3 ) donne -1
rem(7,-3 ) donne 1
Note:
1. Le RESTE de la division a toujours le même signe que le dividende.
2. La relation suivante existe entre les opérateurs "//" et "rem":
30
Langages de Programmation Parallèle, Java & Simula.
Il existe une autre fonction qui est reliée à la division; c'est mod(P,Q) qui donne la fonction
mathématique du modulo. Si P et Q sont positifs alors rem(p,q) et mod(p,q) donne le même
résultat; Autrement, la relation suivante est vraie:
entier(A/B) * B + mod(A,B) = A
Le dernier opérateurs que nous avons étudié est l'exponentiation: "**". En général, le
résultat de l'exponentiation est une valeur real. Le seul cas où le résultat est un
integer, c'est quand les deux opérandes sont de type integer. Dans ce cas, l'exposant
doit être zéro ou positif.
Note:
• & sert à la concaténation de chaînes de caractères
• pour les Booléens, l'égalité est codée avec EQV (équivalent) et non avec '='
• == et =/= servent à comparer l'égalité de pointeurs
Une expression peut aussi utiliser des procédures utilitaires comme sin (sinus), sqrt (racine carrée)
ou ln (logarithme naturel).
L'annexe 2 donne une brève description des procédures utilitaires qui sont fournies avec tout
système Simula. L'exemple ci-dessous fait des calculs numériques:
begin
real x, y, z;
outtext("Y et Z svp: "); breakoutimage;
y := inreal;
z := inreal;
x := sqrt( y ** 2 + ln(z) ** 2);
outtext("X = ");
outreal(x,3,10);
outimage;
end
31
Langages de Programmation Parallèle, Java & Simula.
Les entiers servent à compter les choses ou faire des calculs d'adresses. Les réels sont utilisés pour
des calculs scientifiques, où pour lesquels on utilise des fractions (p.e. 3.14159), des valeurs très
grandes comme la constante d'Avogadro (6.024&23 atomes/mole) ou très petites, comme la masse
d'un électron (9.1083&-28 g).
Conversion de type
Typiquement, on mettra des valeurs entières dans des integer et des réels dans des real; mais on
peut mélanger les types dans une expression ou affecter une valeur d'un type à une variable de
l'autre type. Dans ce cas, il y a conversion automatique de la valeur d'un type à l'autre. En général,
quand on passe d'un entier à un réel, la valeur est inchangée. Par contre, quand on passe d'un réel à
un entier, la fraction est enlevée pour faire un entier. Dans certain langage la valeur est tronquée; en
Simula, la valeur est arrondie et on retourne l'entier le plus proche.
integer i;
real x;
32
Langages de Programmation Parallèle, Java & Simula.
4. Autres déclarations
Pascal a une structure très élaborée de déclarations. SIMULA est moins riche mais plus tolérant.
L'ordre des déclarations importe peu et on n'a pas besoin d'éviter les références FORWARD.
Les tableaux SIMULA sont dynamiques et les bornes peuvent être des expressions quelconques qui
sont évaluées à l'entrée du bloc où le tableau est déclaré.
PASCAL:
A,B : ARRAY [1..10,2..5] OF REAL;
SIMULA:
REAL ARRAY A,B (1:10,2:5);
Mais aussi:
BEGIN
INTEGER N; ..... N:=10;
BEGIN
INTEGER ARRAY A (1:N);
INTEGER ARRAY B (1+ININT : 2*N);
...
END
END
Par contre, les index sont limites a des valeurs entieres et l'affectation entre tableaux ( A:= B ) n'est
pas permise.
Le seul constructeur de type, CLASS, declare des types de structures dynamiques. On montre ici
une application simple mais nous verrons que le concept de CLASS fait la force de SIMULA.
SIMULA PASCAL
CLASS COMPLEX; TYPE
BEGIN COMPLEX= STRUCT
REAL R,I; R,I: REAL;
END; END;
VAR
REF(COMPLEX) C; C: ^COMPLEX;
... ...
C:- NEW COMPLEX; NEW (C);
Nous verrons les classes en plus de détails plus tard ainsi que la déclaration de procédures.
Les étiquettes SIMULA sont des identificateurs déclarés implicitement par leur apparition devant
un énoncé:
L: ;........; GOTO L;
4.1. Enoncés
L’affectation est de la forme:
I:= I+1;
mais aussi,
I:= J:= K:= I+1;
FOR:
En gros il y a la boucle avec un pas (variable) et celle avec une liste de valeurs. Avec une liste, la
variable de contrôle peut être de type arithmétique, caractère, texte, booléens, ou pointeur.
for I:= 1 step I+1 until 100 do ...;
for I:= 100 step -1 until 1 do ...;
for I:= 1,I+3 while I**2 < 100 do ...;
for I:= 2,3,5,7,11 step 4 until 51 do ...;
for C:= 'A','E','I','O','U','Y' do ... ;
for P:- P1,P2,P3 do ...;
4.2. Textes
Les chaînes de caractères en SIMULA sont gérées dynamiquement et les procédures d'accès et de
traitement des chaînes favorisent le traitement séquentiel des caractères. On remarquera donc une
analogie aux entre/sorties. A chaque chaîne est associe un descripteur contenant l'adresse de la
chaîne, sa longueur et l'index du prochain caractère a traiter. Une variable de type TEXT désigne ce
descripteur. Initialement, les variables de texte désignent NOTEXT, la chaîne vide (équivalent a
NONE).
La création de chaînes se fait avec une de deux fonctions:
BLANKS(N) : qui crée une chaîne de N caractères blancs
COPY (T) : qui crée une copie de T.
TEXT T1,T2;
...
T1 :- BLANKS(80);
T2 :- COPY("** IFT 3040 **");
Les opérateurs d'affectation et de comparaison peuvent porter sur les descripteurs ( :-, ==, =/= ) ou
sur le contenu des chaînes ( :=, =, NE ). Voici l’équivalent PASCAL ou on aurait
T1,T2 : ^ ALFA .
SIMULA PASCAL
T1:- T2; T1 := T2;
T1:= T2; T1^:= T2^;
T1 == T2 T1 = T2
T1 NE T2 T1^ <> T2^
On peut aussi tester l'ordre lexicographique de chaînes avec >,>=,< et <=.
Opérateur de concaténation de chaîne: &
text T;
...
outtext( "Error:" & T & "in system") ;
La manipulation du contenu de chaînes se fait a l'aide de procédures et fonctions et la notation (que
nous reverrons avec les CLASS) est celle utilisée en PASCAL pour l'accès a des champs de
STRUCT: la notation de point.
T.LENGTH:
donne la longueur de la chaîne T
T.POS:
donne l'index du prochain caractère à traiter
T.MORE:
TRUE si T.POS > T.LENGTH, FALSE autrement
T.GETCHAR:
retourne prochain caractère et incrémente T.POS
T.PUTCHAR(C):
place le caractère C a l'endroit POS et incrémente POS.
Remarquer la ressemblance avec INCHAR et OUTCHAR.
T.SETPOS(N):
donne la valeur N a T.POS
T.GETINT et T.PUTINT(I):
34
Langages de Programmation Parallèle, Java & Simula.
SIMULA:
PROCEDURE ADD (A,B,C);
NAME C; INTEGER A,B,C;
BEGIN
C:= A+B;
END;
35
Langages de Programmation Parallèle, Java & Simula.
Paramètres de procédures
mode de passage
type de paramètre
VALUE REF NAME
- real,int,bool ou char D X O
- text ou array de
O D O
(real,int,bool,char)
- ref(..) ou array de (ref,text) X D O
- procedure,label ou switch X D O
Paramètres de Classe
mode de passage
type de paramètre
VALUE REF
- real,int,bool ou char D X
- text ou array de
O D
(real,int,bool,char)
- ref(..) ou array de (ref,text) X D
Ces tableaux semblent à première vue un peu compliques sans raison. Par exemple, pourquoi ne
peut-on pas passer une REFerence par VALUE ou quelle est la différence entre le passage d'un
texte par VALUE ou par REFerence? La réponse est que la notion de passage par valeur, dans le
cas d'une structure de liste ou de structures pointées, est quelque peu ambiguë. Le passage par
valeur est suppose empêcher les effets de bords en créant une copie locale du PA. En fait le passage
par value d'un pointeur en PASCAL protège efficacement la variable pointeur passée comme
paramètre; mais le contenu de l'objet pointe n'est nullement protège. Dans ce cas, un VRAI passage
par valeur exigerait une copie complète non seulement de l'objet pointe mais aussi de tout autre
objet atteignable par des pointeurs dans cet objet. Pour les pointeurs (variables REF), ce qui serait
appelé en PASCAL le passage par valeur est appelé en SIMULA passage par référence et le passage
par VALUE est interdit, C.A.D. le pointeur utilise en paramètre est protége, mais la structure
pointée ne l'est pas.
A peu près la même chose s'applique au TEXTs. Une variable TEXT en SIMULA est un
descripteur qui contient, entre autre, un pointeur vers une chaîne de caractères et un indicateur,
POS, de l'endroit ou on est rendu dans le traitement de cette chaîne. Dans ce cas, le passage par
défaut (mode REF) implique une copie locale du descripteur: le descripteur (PA) est donc protège
mais la chaîne elle même peut être changée. Pour le passage par VALUE, on fait une copie et de la
chaîne et du descripteur (avec POS remis à 0).
6. Aspects avancés
6.1. Classes et objets
La puissance de SIMULA réside dans son concept de CLASS: la spécification d'un ensemble
d'objets du même type..
Une déclaration de CLASS définit un type d'OBJET dynamique. Ces objets ressemblent au
RECORDs de PASCAL dans le sens qu'ils ont des attributs (champs) accessibles par notation
pointée (ex: P.A ) et ils ressemblent aux procédures dans le sens qu'une CLASS peut avoir des
énoncés et des paramètres. En plus, la PREFIXATION permet le traitement rationnel d'objets avec
variantes et les objets peuvent fonctionner en COROUTINES. Finalement, SIMULA gère
l'allocation dynamique de façon très sécuritaire en initialisant tout pointeur a NONE et en
récupérant automatiquement l'espace occupe par des objets inaccessibles.
36
Langages de Programmation Parallèle, Java & Simula.
Prenons un premier exemple graphique. Un POINT est défini par ses coordonnées rectangulaires X
et Y. Un autre attribut est sa distance DIST de l'origine. On peut déclarer le type POINT avec
CLASS POINT;
BEGIN
REAL X,Y,DIST;
END;
Les objets spécifies par des classes doivent être créées dynamiquement par l'opérateur NEW et on
les accède par des pointeurs (REFERENCEs).
REF(POINT) P;
...
P:- NEW POINT;
P.X:= 1; P.Y:= 3.0;
P.DIST:= SQRT (P.X**2 + P.Y**2);
Voyons l'analogie avec les procédures avec une autre version de POINT. Ici on met X et Y en
position paramètres pour exiger une valeur initiale à la création et on met un énoncé pour calculer la
valeur de DIST.
CLASS POINT (X,Y); REAL X,Y;
BEGIN
REAL DIST;
A la création, X et Y reçoivent les valeurs 1 et 3 et le corps de POINT est exécuté avant de revenir à
l'énoncé de création. POINT fonctionne comme une procédure à la différence que le "bloc
d'activation" n'est pas détruit au retour et qu'on peut accéder au variables locales par le pointeur:
P.X, P.Y et P.DIST .
Les attributs accessibles d'un objet ne sont pas limites a des variables; on peut aussi avoir des
procédures et fonctions locales. Ceci permet d'intégrer les opérations permises sur un type d'objet à
la déclaration de sa classe. Ici l'attribut DIST dépend des valeurs X et Y et un changement de X ou
Y entraîne un changement de DIST. Il est plus élégant de déclarer DIST comme attribut fonctionnel
qui calcule la bonne valeur chaque fois qu'on en a besoin:
CLASS POINT (X,Y); REAL X,Y;
BEGIN
REAL PROCEDURE DIST;
BEGIN DIST:= SQRT(X**2 + Y**2) END;
END;
La distance du point P est donnée par P.DIST et remarquer que DIST étant une fonction on ne peut
pas lui affecter une valeur avec P.DIST:=5 .
6.2. Simset
Nous avons vu que la préfixation d'une classe par le nom d'une autre lui ajoutait tous les attributs,
déclarations et énoncés du préfixe. La préfixation s'applique aussi au BLOCs et aux programmes.
Par ce biais, SIMULA permet une extension du langage. SIMULA à deux classes prédéfinies,
SIMSET et SIMULATION, que l'usager peut utiliser comme préfixe. SIMSET contient des
déclarations utiles pour le traitement de listes et SIMULATION sert a la simulation. Les listes de
SIMSET sont circulaires à deux sens avec têtes de listes. Trois classes sont définies: HEAD qui
décrit les têtes de listes et comprend les procédures et fonctions s'appliquant aux listes, par exemple
FIRST pour donner le premier élément d'une liste; LINK que l'usager utilise comme préfixe aux
objets qui seront membres de listes; et LINKAGE, préfixe commun a HEAD et LINK afin de
permettre le chaînage. Voici le squelette de SIMSET.
CLASS SIMSET;
BEGIN
CLASS LINKAGE;
BEGIN
REF(LINK) PROC SUC ; ...;
REF(LINK) PROC PRED; ...;
REF(LINKAGE) PROC PREV; ...;
END;
37
Langages de Programmation Parallèle, Java & Simula.
REF(HEAD) LISTE;
REF(ELEMENT) P;
P:- LISTE.LAST;
WHILE P=/= NONE DO
BEGIN
OUTCHAR(P.C); P:-P.PRED;
END;
END
6.3. Coroutines
Les objets de SIMULA fonctionnent comme des co-routines. Pour comprendre les co-routines,
regardons d'abord comment marche l'appel de procédure. Quand une procédure P1 appelle une
procédure P2: 1) une copie de P2 est créée, 2) le contrôle passe au début de P2, 3) P2 exécute
jusqu'a la fin, 4) on détruit P2 et 5) le contrôle revient a P1. Il existe une relation maître-esclave
entre P1 et P2.
38
Langages de Programmation Parallèle, Java & Simula.
Avec deux coroutines P1 et P2, le passage de contrôle se fait d'égal à égal. Pour passer le contrôle à
P2, P1 fera RESUME (P2). Pour revenir a P1, P2 fera RESUME(P1). Noter qu'une coroutine
activée par RESUME continue la ou elle était quand elle a passe le contrôle a quelqu'un d'autre, pas
au début. Noter aussi qu'un "retour" n'implique pas la destruction de la routine.
La situation est légèrement compliquée par le problème de création et de fin des routines. Quand
une coroutine passe à travers son END final, à qui passer le contrôle? Pour expliquer ceci, on
suppose que chaque coroutine a un pointeur cache RETOUR qui peut designer soit une autre objet,
soit le bloc englobant ou se trouve sa déclaration. Un objet passe le contrôle a RETOUR avec
l'instruction DETACH qui a l'effet suivant:
temp :- RETOUR;
RETOUR:- "bloc englobant";
RESUME (temp);
Notons que la fin d'une coroutine est équivalente a un DETACH.
Maintenant voyons la création. Quand P1 exécute
P2 :- NEW C;
BEGIN
INTEGER U,N;
U:= 12345;
N:= ININT;
BEGIN
REF(J) ARRAY JOUEUR (1:N);
INTEGER I;
SUIVANT := MOD(MOI,N)+1;
DETACH;
WHILE SUM < 100 DO BEGIN
SUM := SUM + RANDINT (1,6,U);
RESUME(JOUEUR(SUIVANT));
END;
OUTINT(MOI,5); OUTTEXT(" A GAGNE"); OUTIMAGE;
END;
39
Langages de Programmation Parallèle, Java & Simula.
RESUME(JOUEUR(1));
OUTTEXT("-- FIN DU JEU --");
END;
END
7. Aspect parallèle
7.1. Simulation
SIMULATION est une classe standard qui introduit le concept de PROCESS afin de décrire des
objets dont la synchronisation est basée sur l'évolution du temps. Avec cette class comme préfixe,
l'usager n'utilise plus les primitives RESUME, DETACH et CALL qui font des transferts de contrôle
explicites. Par contre, des procédures de plus haut niveau sont fournies pour qu'un PROCESS qui
veut s'arrêter temporairement puisse indiquer l'heure (EVTIME) à laquelle il désire continuer. Tous
les PROCESS actifs sont chaînes dans un échéancier SQS par ordre croissant de EVTIME et l'arrêt
d'un process entraîne l'activation automatique du process en tête de SQS. (Noter que le "temps" est
simulé et n'a aucun rapport avec l'écoulement réel du temps de calcul; les evtimes servent à imposer
une relation d'ordre entre le phases de calcul des différents process). Voici le squelette de la classe
SIMULATION.
SIMSET CLASS SIMULATION;
BEGIN
LINK CLASS PROCESS;
BEGIN
BOOL PROC TERMINATED;...
BOOL PROC IDLE ;...
REAL PROC EVTIME ;...
REF(PROCESS) PROC NEXTEV;...
DETACH;....
END;
{ REF(HEAD) SQS ; }
REF(PROCESS) PROC CURRENT;...
REAL PROC TIME ;...
REF(PROCESS) MAIN ;
END;
Notes:
• SIMULATION est préfixé par SIMSET pour donner accès au traitement de listes.
• Un PROCESS est préfixé par LINK. Le chaînage dans SQS étant indirect, un process peut
être à la fois dans SQS et une seule autre liste.
• Pour raison de sécurité, la liste SQS est inaccessible à l'usager. Par contre CURRENT est une
fonction qui retourne une référence sur le premier process de SQS. Par définition, ce premier
process est celui qui est en exécution.
• TIME retourne CURRENT.EVTIME, c.a.d. l'heure courante.
• Le programme peut agir comme un process et il est designé par MAIN.
40
Langages de Programmation Parallèle, Java & Simula.
Le premier énoncé de PROCESS est DETACH. La création d'un process ne le fait donc pas
démarrer. SIMULATION contient aussi un certain nombre de procédures de "scheduling" qui
manipulent les process dans SQS. Ces procédures opèrent par défaut sur CURRENT et toutes se
terminent en passant le contrôle au premier process de SQS (en général un nouveau CURRENT).
Avec les options AT et DELAY, P est placé derrière tout autre process cédulé pour la même heure
(FIFO). Cependant, on peut demander a le mettre devant les autres avec le mot clé PRIOR:
REACTIVATE P DELAY 10 PRIOR;
Noter que les trois énoncés suivants ont tous le même effet:
REACTIVATE P DELAY 0 PRIOR;
REACTIVATE P;
REACTIVATE P BEFORE CURRENT;
Les cas bizarres, P==NONE, P2==NONE, P2.IDLE, P==P2 etc... ne produisent aucun effet.
Le deuxième énoncé d'activation ACTIVATE est identique a REACTIVATE si P.IDLE est vrai (P
n'est pas dans SQS), autrement si P est déjà dans SQS, ACTIVATE n'a aucun effet et P reste ou il
était.
Voici un programme qui simule une file d'attente avec des PROCESS client. Pour montrer
l'évolution de la taille de la queue, on utilise un process reporter qui imprime le nombre de
personnes dans le système à toute les 10 unités de temps. La simulation dure 200 unités de temps.
L'exemple montre aussi l'emploi de procédures de traitement de listes: into, out et empty.
! Exemple de la simulation d'une file d'attente ;
Simulation begin
ref(head) Q;
INteger U, N;
Boolean Guichet_Occupe;
N := N+1;
if Guichet_occupe then begin
into(Q);
passivate;
out;
end;
Guichet_occupe := TRUE;
hold( uniform( 0,18, U ) );
Guichet_occupe := FALSE;
41
Langages de Programmation Parallèle, Java & Simula.
begin integer i;
outint(time, -6);
for i := 1 step 1 until N do outchar('*');
outimage;
hold(10);
end;
Q :- new Head;
U := clocktime;
hold(200);
outtext("=== Fin de la simulation ===");
end
7.2. Parallélisme
Les processus de SIMULA travaillent en quasi-parallèle: a tout moment, un seul est actif. De plus,
un processus qui n'appelle pas de procédure ou d'énoncé de scheduling est ininterruptible et TIME
reste fixe durant son exécution. Pour modéliser le fait que le travail d'un processus prend un certain
temps et que d'autres travaillent en parallèle, il faut insérer des énoncés HOLD(...) aux endroits
appropries ou ... représente la "durée" des actions du processus.
L'exemple suivant démontre les problèmes de synchronisation dans les systèmes d'exploitation. On
simule 5 processus qui incrémentent chacun la variable globale N 10 fois. On s'attendrait a ce que N
vaille 50 à la fin de la simulation. En fait, à cause du délai entre l'accès et la mise a jour de N, cette
valeur sera moindre. On simule ce délai avec une procédure TRANSFER qui fait un HOLD
aléatoire et on insère un HOLD dans le processus.
simulation begin
integer i,n,u;
integer procedure transfer(i); integer i;
begin
transfer := i;
hold(uniform(0,2,u));
end;
u:= 47;
for i:= 1 step 1 until 5 do
activate new proc;
outtext("n devrait valoir 50"); outimage;
hold(10000);
outtext("n="); outint(n,5); outimage;
end;
L'exécution donne
N DEVRAIT VALOIR 50
N= 14
42
Langages de Programmation Parallèle, Java & Simula.
Conclusion
Nous avons présenté deux langages de programmation orientés objets qui représentent presque deux
bornes historiques en ce domaine ; Simula le plus ancien -et qui fait encore ces preuves surtout sur
le plan pédagogique-, Java le plus récent et qui fait la une des langages du troisième millénaire
orienté réseau. La puissance du concept d’objet introduit par les deux langages, leur permet de
concevoir et produire des applications parallèles par excellence. Alors que Simula utilise la notion
de simulation, d’événement et de gestion de processus ; Java, qui prétend être multi-usage et
portable, introduit le concept de thread (processus léger) et le mécanisme de moniteur et de
synchronisation.
En effet, la modélisation des processus concurrents se fait avec divers modèles comme la théorie
des files d’attente, les réseaux de Petri ou les compteurs abstraits. Cette notion de processus a
évolué pour faire apparaître un grain d’activité plus fin, le processus léger qui introduit de la
concurrence à l’intérieur d’un acteur doté d’un espace d’adressage. Elle devrait évoluer pour
exprimer une séquence d’actions qui se déroulent sur divers sites d’un système réparti et qui sont
mises en relation par des messages.
Nous pensons qu’à travers la panoplie d’exemples que nous avons exposés, le lecteur a eu une idée
claire et assez fine sur les deux langages. Ceci n’exclue la nécessité de pratiquer la programmation
en codant lui même ses propres chefs-d’œuvre.
Bibliographie
1. Birtwistle, G.M., O.-J. Dahl, B. Myhrhaug and K. Nygaard. "SIMULA Begin." p. 391,
AUERBACH Publishers Inc, 1973.
2. Dietel & Deitel, Java How to Program, Fourth Edition, Prentice Hall 2002.
43