Vous êtes sur la page 1sur 6

University of Boumerdes, Mhamed Bougara. Faculty of Science.

Department of
Computer Science
Network Programming -Master 1 2022-23-
Series n° 3
Exercice 1 : Concurrence
Soit la classe Resource ayant une chaine de caractères str comme propriété et les méthodes addChar
(int) qui ajoute une lettre de l’alphabet à str et addInt(int) qui ajoute un entier à str. Soit deux classes
threads Thd1 et Thd2 tel que Thd1 réalise l’ajout des caractères de l’alphabet et Thd2 ajoute des entiers
entre 1 et 26 (ie. Thd1 appelle addChar() et Thd2 addInt()) .
• Ecrire le code de la classe Resource
• Ecrire le code des deux threads
• Ecrire un programme principal tel que :
• Créer une seule ressource commune
• Créer deux threads T1 (de type Thd1) et T2 (de type Thd2) chacune de type différent
• Démarrer les threads et afficher la taille de la chaine produite par les deux
• Quelle est la remarque si on exécute le programme plusieurs fois.
• Ajouter le mot clé synchronized à l’entête des deux méthodes de la classe Resource.
• Quelle est votre remarque.
Exercice 2 programmation parallèle
Nous voulons effectuer la somme des entiers inférieures à un nombre n à l’aide de m threads. Le thread
reçoit la valeur du début de l’intervalle et celle de la fin, ensuite il sauvegarde le résultat dans une
variable d’objet. Le programme principal calcule le total par l’addition des sommes partielles trouvées
par les m threads.
Exemple :

si n = 10 et m = 2, alors le thread 1 calcule : 1+2+3+4+5 = 15 et le thread 2 calcule : 6+7+8+9+10 = 40


Total = 45.
Donner le code source, ensuite tester le programme pour n = 1000 et m = 4.
Exercice 3 producteur/consommateur
On désire développer une petite application simulant les comportements concurrents d'un producteur
et d’un consommateur de messages. D'un côté, le producteur produit des caractères qu'ils stocke dans
un buffer ; de l'autre cote, le consommateur récupère dans ce même buffer les caractères (dans l'ordre
où ils y ont été placés).
On doit respecter un certain nombre de contraintes et pouvoir paramétrer l'application :
• Un producteur ne peut produire un message que si le buffer n'est pas plein.
• Un consommateur ne peut lire un caractère que si le buffer n'est pas vide.
On définit les classes suivantes :
class buffer { Buffer(int size){}//constructeur
Put(char c){} //la méthode qui nous permet de déposer une caractère dans le buffer
Char Get(){} // la méthode qui nous permet de retirer une caractère à partir du
buffer
}
class producteur extends Thread{ producteur(Buffer b){}} //pour implémenter le thread
producteur.
class consommateur extends Thread{consommateur(Buffer b){}} //pour implémenter le
thread consommateur

Développer ces classes, utiliser le modificateur synchronized pour synchroniser le producteur et le


consommateur ainsi que les méthodes wait() et notify().

Correction
Exercice 1
class Ressource {
private String str;
public Ressource() {
this.str = new String ("");
}
public synchronized void addChar(int c) {
this.str+=(char)c;
}

public synchronized void addNum (int n) {


this.str+=n;
}

public String getStr() {


return this.str;
}
}

class Thd1 extends Thread {


private Ressource r1;
public Thd1 (Ressource r) {
this.r1 = r;
}

public void run () {


for (int i = 0 + (int)'A'; i<= (int)'Z'; i++)
this.r1.addChar(i);
}
}

class Thd2 extends Thread{


private Ressource r1;
public Thd2 (Ressource r) {
this.r1 = r;
}

public void run () {


for (int i = 0 ; i<= 26; i++)
this.r1.addNum(i);
}
}

public class TEST {


public static void main(String a[]) throws InterruptedException {
Thread T1, T2;
Ressource res = new Ressource();
T1 = new Thd1(res);
T2 = new Thd2(res);
T1.start();
T2.start();

T1.join();
T2.join();

System.out.println(res.getStr()+" \n numbre char :


"+res.getStr().length());
}
}
Exercice 2
class CalculThread extends Thread { // 01 dérivée de Thread
private int debut, fin, tnbr;
private long resultat;
static int numThread = 1;

public CalculThread(int debut, int fin) { // constructeur


this.debut = debut;
this.fin = fin;
tnbr = CalculThread.numThread++;
}

public long getResultat() { // retourne la somme partielle


return resultat;
}

public void run() { // 02 la fonction principale du thread


resultat = 0;
for (int i = debut; i <= fin; i++) {
resultat += i;
System.out.println("Thread n : "+tnbr);
}
}
}

public class ExempleThread {


public static void main(String[] args) {
int debut = 1;
int fin = 1000;
int nbThreads = 4;

// 4 threads tel que: T1 [1, 250], T2 [251, 500], T3 [501, 750], T4 [751,
1000]
CalculThread[] threads = new CalculThread[nbThreads];
int pas = (fin - debut + 1) / nbThreads; // ici le pas est 250

for (int i = 0; i < nbThreads; i++) {


// calcul du debut et fin
int debutThread = debut + i * pas;
int finThread = (i == nbThreads - 1) ? fin : debutThread + pas - 1;
// creation des threads
threads[i] = new CalculThread(debutThread, finThread);
threads[i].start(); // 03 démarrer le thread
}

long resultatTotal = 0;
for (int i = 0; i < nbThreads; i++)
try {
// attendre que le thread termine
threads[i].join();
resultatTotal += threads[i].getResultat(); // recuperer la somme
partielle
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Le résultat du calcul est : " + resultatTotal);
}
}

Exercice 3

import java.util.Random;

class Buffer {

private char buff[]; // la ressource partagée -> un vecteur


private int taille; // la taille du vecteur définit à l'initialisation
private int compteur; // compte le nombre d'élément dans buff[]
private int index; // pointeur sur la prochaine case à remplir (circulaire c-a-d revient au début)

public Buffer(int taille) { // constructeur initialise le buff[]


this.taille = taille;
compteur = 0;
index = 0;
buff = new char[taille];
}

synchronized public void put(char c) { // méthode pour déposer des éléments dans le buff[], synchronized pour
assurer l'accès d'un seul thread à cette méthode donc un élément est ajouter à la fois par un Producteur
while (compteur == taille) { // la condition de mise en veille de thread Producteur est : tant que le buff[] est
plein le producteur ne peut pas ajouter alors il attent q'un place soit libérée
try {
wait(); // mise en attente du thread Producteur
} catch (InterruptedException ex) {
System.out.println("Erreur " + ex);
}
} // cette condition est testée en permanence jusqu'à ce que le buff a de la place donc

buff[index] = c; // ajouter un caractère au buff[] à la case libre (index)


index++; // avancer l'indice de la case vide
compteur++; // incrimenter le nombre d'élément
notify(); // eveiller les threads en attente
System.out.println(" in <- " + c); // affichage
}

synchronized public char get() { // méthode pour retirer des éléments du buff[], retourne un char
while (compteur == 0) { // la condiction ici c'est: tant que le buff[] est vide alors le consommateur n'a rien à
consommer donc il attent
try {
wait();
} catch (InterruptedException ex) {
System.out.println("Erreur " + ex);
}
}
char car = buff[index - 1]; // recuperer le caractère
buff[index - 1] = ' '; // effacer le caractère
index--; // recuperer la case correspondante
compteur--; // décrimenter le nombre d'éléments dans buff[]
notify(); // eveiller les threads en attente
return car; // retourner le caractère
}
}

class Poper extends Thread { // Le thread Consommateur

private final Buffer buffer; // très important, c'est L'OBJET BUFFER commun entre le Producteur et le
Consommateur

public Poper(Buffer buffer) { // constructeur pour transférer le Buffer au Consommateur


this.buffer = buffer;
}

@Override // surcharger la méthode run


public void run() { // important implémentation de la méthode run du thread
while (true) { // boucle infinit
System.out.println(" out -> " + buffer.get()); // lire un caractère du buffer
}

}
}

class Pusher extends Thread { // le thread Producteur


private Buffer buffer; // l'objet buffer commun

public Pusher(Buffer buffer) { // transferer le buffer au Producteur


this.buffer = buffer;
}

@Override
public void run() {
while (true) {
Random rand = new Random(); // création d'un objet Random
buffer.put((char) (rand.nextInt(26) + 65)); // générer un caractère et l'insérer dans le buffer
}
}
}

public class Exercice4 { // classe de test

public static void main(String[] args) {


Buffer buffer = new Buffer(10); // créer un buffer de taille 10
Pusher pusher = new Pusher(buffer); // créer un Producteur et lui envoyer le buffer
Poper poper = new Poper(buffer); // créer un consommateur et lui envoyer le buffer
pusher.start(); // démarrer le thread

poper.start(); // démarrer le thread


}
}
// notez que: les méthodes de gestion du buffer sont dans la classe Buffer
// et que tous les controles d'accès (synchronized) et la mise en attente (wait) sont implémentés dans la même
classe

Vous aimerez peut-être aussi