Bonjour à tous,
[Je re-crée ce topic suite au problème qu'a connu le SGBD de ZdS]
Contexte
Je dois mettre en place une machine à sous de N
rouleaux qui tournent de façon indépendante. Chacun d'eux est géré par un thread (qui attend 200ms entre chaque incrémentation du compteur). Un thread gère l'affichage des rouleaux toutes les 500ms. Le système est donc de type lecteur-rédacteurs, avec un seul lecteur.
Ma solution
J'ai créé trois classes :
1 - Counter
. Chaque instance est associée à un et un seul thread-rouleau, et chaque rouleau a un et un seul objet :Counter
.
1 2 3 4 5 6 7 8 9 | public class Counter { int value; public Counter(int value) { this.value = value; } public int getVal() { return value; } public void setVal(int v) { value = v; } public void inc() { value++; } } |
2 - La classe Launcher
. Elle affiche la valeur de l'objet :Counter
de chaque thread-rouleau.
Voici le bout de code le plus important de cette classe (l'affichage de ladite valeur). Le code entier est affiché juste après.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | try { while (true) { // Note that writers have also "while(true)" to increment for(Writer writer : writers) { // We display each writer's counter synchronized (writer.cmpt) { System.out.print(writer.cmpt.getVal()); if(writers.get(writers.size()-1) != writer) { System.out.print(" - "); } } } System.out.println(); Thread.sleep(500); } } catch(InterruptedException e) { System.out.println(e); } |
Code entier de Launcher
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import java.util.ArrayList; public class Launcher { public static void main(String[] args) { int n = 3; // Number of threads (ie. : number of rollers) ArrayList<Writer> writers = new ArrayList<Writer>(); while(n-- > 0) { // We start all the writers Writer writer = new Writer(); writers.add(writer); writer.start(); } try { while (true) { // Note that writers have also "while(true)" to increment for(Writer writer : writers) { // We display each writer's counter synchronized (writer.cmpt) { System.out.print(writer.cmpt.getVal()); if(writers.get(writers.size()-1) != writer) { System.out.print(" - "); } } } System.out.println(); Thread.sleep(500); } } catch(InterruptedException e) { System.out.println(e); } } } |
3- Enfin, la classe Writer
, c'est-à-dire thread-rouleau.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class Writer extends Thread { public Counter cmpt; public Writer() { cmpt = new Counter(0); } public void run() { try { while (true) { // Note that READER has also "while(true)" to DISPLAY synchronized (cmpt) { cmpt.inc(); if (cmpt.getVal() >= 10) { cmpt.setVal(0); } Thread.sleep(200); } } } catch(InterruptedException e) { System.out.println(e); } } } |
Comme vous pouvez le voir, aucun thread-rouleau ne partage son :Counter
avec un autre thread-rouleau.
Le thread-main, qui s'occupe de l'affichage de la valeur des compteurs, ne doit pas lire celle-ci quand un thread-rouleau est en train d'écrire dedans (système lecteur-rédacteurs). D'où le synchronized
présent dans Launcher
et Writer
.
Le problème
Le souci, c'est que quand j'exécute le programme, le thread-main affiche chaque ensemble de rouleaux (ie. : "0 - 2 - 1" par exemple) petit-à-petit : ici il afficherait dans un premier temps, par exemple, "0 - 2 - " et ensuite le " 1" ce qui donnerait, sur la même ligne : "0 - 2 - 1" mais dans un second temps.
Et je doute que le prof soit d'accord avec ça parce que ce n'est pas comme ça qu'une machine à sous de la vraie vie fonctionne. Si je ne me trompe pas, c'est à cause de l'exclusion mutuelle lecteur-rédacteurs : le lecteur n'affiche pas tant qu'un rédacteur écrit.
Du coup rien de plus normal, puisque c'est ce qu'on veut faire. Mais on veut aussi que chaque ensemble de rouleaux, c'est-à-dire chaque ligne de la console, s'affiche d'un coup. Tout en respectant le délai d'affichage de 500ms.
Du coup je ne sais pas trop quoi faire… Le comportement de mon programme me semble normal, mais pour autant ne doit certainement pas répondre aux exigences du prof…
Quelqu'un aurait-il une idée sur ce qu'il serait possible de faire ?
Merci d'avance !