Compare commits

6 Commits

Author SHA1 Message Date
Rochas
8c455cffad correction uml 2025-12-21 20:41:04 +01:00
Rochas
c6a84f55e1 correction 2 2025-12-21 16:26:46 +01:00
Rochas
16c2f5bdc3 correction 2025-12-21 15:53:35 +01:00
tuanvu
3ad1ffe03c update mermaid 2025-12-21 13:59:07 +01:00
tuanvu
63fa3e966b test mermaid 2025-12-21 12:56:08 +01:00
tuanvu
4319e7d6d1 test plantuml 2025-12-21 12:41:30 +01:00
9 changed files with 152 additions and 30 deletions

153
README.md
View File

@@ -7,22 +7,144 @@
## Diagramme de classe UML :
```mermaid
classDiagram
Capteur <|.. CapteurImpl
AlgoDiffusion <|.. DiffusionAtomique
AlgoDiffusion <|.. DiffusionEpoque
AlgoDiffusion <|.. DiffusionSequentielle
CapteurAsync <|.. Canal
ObserverDeCapteurAsync <|.. Canal
ObserverDeCapteur <|.. Afficheur
Callable <|.. UpdateReq
Callable <|.. GetValueReq
Canal "1" --> "1" ObserverDeCapteur
CapteurImpl "1" o-- "0..*" ObserverDeCapteurAsync
CapteurImpl "1" --> "1" AlgoDiffusion
Canal "1" --> "1" Capteur
Canal "1" --> "1" Scheduler
class Capteur{
<<interface>>
+attach(o: ObserverDeCapteurAsync):void
+tick() :void
+getValue():int
+getValueDiffusion():int
}
class CapteurImpl{
-value : int
-diffusion : AlgoDiffusion
#observers : List~ObserverDeCapteurAsync~
-lock : boolean
-initialTime : long
+attach(o: ObserverDeCapteurAsync):void
+tick() :void
+setAlgoDiffusion( diffusion: AlgoDiffusion) : void
+getValue():int
+getValueDiffusion():int
+stop() : void
+isStop() :void
}
class AlgoDiffusion{
<<interface>>
+execute() : void
+getValue() : int
}
class DiffusionAtomique{
+capteur : CapteurImpl
-futures : List~Future~?~~
-values : Queue~Integer~
+DiffusionAtomique(c:CapteurImpl)
+execute():void
+getValue():int
}
class DiffusionEpoque{
+capteur : CapteurImpl
-futures : Future~?~[]
+DiffusionEpoque(c:CapteurImpl)
+execute():void
+getValue():int
}
class DiffusionSequentielle{
+capteur : CapteurImpl
-futures : List~Future~?~~
-value : int
+DiffusionSequentielle(c:CapteurImpl)
+execute():void
+getValue():int
}
class CapteurAsync{
<<interface>>
getValue() : Future~Integer~
}
class ObserverDeCapteurAsync{
<<interface>>
update() : Future~?~
}
class Canal{
- scheduler : scheduler
- afficher : ObserverdeCapteur
- capteur : Capteur
+Canal(capteur: Capteur, scheduler: Scheduler, afficher: ObserverdeCapteur)
+update() : Future~?~
+getValue() : Future~Integer~
}
class ObserverDeCapteur{
<<interface>>
update(capteurAsync : CapteurAsync) : void
}
class Afficheur{
-id : int
+vals : ArrayList~Integer~
+setId(id : int): void
+update(capteurAsync : CapteurAsync)
}
class Callable~V~{
<<interface>>
call() : V
}
class GetValueReq{
-capteur : Capteur
+GetValueReq(capteur : Capteur)
+call() : Integer
}
class UpdateReq{
-canalProxy : CapteurAsync
-afficheur : ObserverdeCapteur
+UpdateReq(canalProxy : CapteurAsync, afficheur : ObserverdeCapteur)
+call() : Void
}
class Scheduler{
- scheduler : ScheduledExecutorService
+ Scheduler(nbCanaux : int)
+ getScheduler(): ScheduledExecutorService
+ enquete(task : Callable<T>, delay : long) : Future~T~
}
```
## Stratégies de diffusions :
Nous avons ajouté dans l'interface ``AlgoDiffusion`` la fonction ``getValue()``, cette fonction permet de retourner une valeur du capteur gardé en mémoire par l'algorithme de diffusion. La valeur gardée en mémoire est gérée différemment en fonction de la stratégie de diffusion.
Nous avons ajouté dans l'interface ``AlgoDiffusion`` la fonction ``getValue()``, elle permet de retourner une valeur du capteur gardé en mémoire par l'algorithme de diffusion. La valeur gardée en mémoire est gérée différemment en fonction de la stratégie de diffusion.
On a donc aussi ajouté à l'interface ``Capteur`` la focntion ``getValueDiffusion()`` permettant de récupérer la valeur de l'algo de diffusion.
### - Diffusion Atomique :
La diffusion atomique permet que tous les afficheurs affichent toutes les valeurs du capteur, ils affichent donc les mêmes valeurs.
Le capteur change de valeur toutes les 500 ms alors que les canaux prennent entre 2s et 3s pour passer à la valeur suivante, les afficheurs prennent donc du retard. Si les capteurs tournent 1h, les afficheurs auront jusqu'à 5h de retard et au mieux 3h de retard.
La diffusion atomique permet que tous les afficheurs affichent chacun toutes les valeurs du capteur.
Le capteur change de valeur toutes les 500 ms alors que les canaux prennent entre 2s et 3s pour passer à la valeur suivante, les afficheurs prennent donc du retard. Si les capteurs tournent 1h, les afficheurs auront jusqu'à 5h de retard.
On doit donc enregistrer les valeurs du capteur dans une file d'attente ``Queue<Integer> values``. Alors ``getValue()`` de l'aglo de diffusion n'a qu'à faire un ``peek()`` sur cette file d'attente. À chaque appel de ``execute()`` on rajoute la valeur.
On doit donc enregistrer les valeurs du capteur dans une file d'attente ``Queue<Integer> values``. Alors ``getValue()`` de l'aglo de diffusion n'a qu'à faire un ``peek()`` sur cette file d'attente. Et à chaque appel de ``execute()`` on rajoute la valeur à la file.
Pour que les canaux soient synchronisés, on a une liste ``List<Future<?>> futures`` qui stocke les Future en cours de traitement (cette liste a donc au maxium comme taille le nombre de canaux).
À chaque appel de ``execute()``, on retire de la liste les Future terminés, quand la liste est vide alors ils sont tous terminés, on retire l'élément à la file d'attente, et on relance des nouveaux Future en faisant un ``update()`` sur chaque canal.
À chaque appel de ``execute()``, on retire de la liste les Future terminés, quand la liste est vide alors ils sont tous terminés et on retire la valeur qui vient de finir d'être traitée de la file d'attente, et on relance de nouveaux Future en faisant un ``update()`` sur chaque canal.
### - Diffusion Sequencielle :
### - Diffusion Séquentielle :
Ici, il faut simplement que les afficheurs aient des valeurs synchronisées et que les valeurs soient dans l'ordre chronologique. On n'a donc pas besoin d'afficher toutes les valeurs du capteur.
@@ -34,36 +156,35 @@ On a encore une liste ``List<Future<?>> futures`` qui a le même fonctionnement
Cette dernière stratégie est la plus simple, les afficheurs doivent juste afficher chacune des valeurs dans l'ordre chronologique. Il n'y a donc pas de synchronisation entre les afficheurs, et pas non plus besoin d'afficher toutes les valeurs.
Il nous reste donc plus que ``futures``, mais cette fois en tant que tableau de taille fixe ``Future<?>[] futures`` (nombre de canaux). On n'a pas besoin d'attendre que tous les Future soient finis pour passer à la suite, dès qu'un Future est fini, on relance directement un update() sur le canal associé.
Il nous reste donc plus que la liste ``futures``, mais cette fois en tant que tableau de taille fixe ``Future<?>[] futures`` (avec comme taille le nombre de canaux). On n'a pas besoin d'attendre que tous les Future soient finis pour passer à la suite, dès qu'un Future est fini, on relance directement un update() sur le canal associé.
La fonction ``getValue()`` retourne donc directement la valeur courante du capteur sans rien sauvegarder au préalable.
## Tests :
### - Tests :
L'exécution dans chaque test on environ la même forme :
- on initialise les afficheurs, le Sceduler, le capteur, l'algo de diffusion, les canaux
L'exécution dans chaque test ont environ la même forme :
- on initialise les afficheurs, le Scheduler, le capteur, l'algo de diffusion, les canaux
- on lance le tick avec le scheduler.
- on laisse tourner pendant quelques secondes (5s pour la stratégie atomique, et 10s pour les 2 autres)
- on attend les potentiels derniers Future (25s pour la stratégie atomique, et 3s pour les 2 autres)
- affichage des résulat des afficheur pour debug
- affichage des résulat des afficheurs pour debug
ps : Pour l'ago de diffusion atomique une constante ``TEST_TIME`` est au début du test pour modifier la durée totale du test (1/6 de run + 5/6 d'attente)
ps : Pour l'ago de diffusion atomique une constante ``TEST_TIME`` est au début du test pour modifier la durée totale du test (1/6 de run + 5/6 d'attente).
Dans l'afficheur, nous avons ajouté une liste ``ArrayList<Integer> vals`` permettant de sauvegarder les valeurs affichées, qui sera utilisée ensuite par l'oracle.
### - Oracle
Notre capteur envoie des valeurs de 1 en 1 à chaque ticket en commençant par 1
Notre capteur envoie des valeurs de 1 en 1 à chaque tick en commençant par 1.
#### - Diffusion Atomique
On a deux oracles :
- Un qui vérifie que les éléments sont strictement croissants de 1 en 1 en commençant par 1
- Un qui vérifie que les éléments sont strictement croissants de 1 en 1 en commençant par 1.
- Et un second qui vérifie que tous les canaux ont les mêmes éléments entre eux.
#### - Diffusion Sequencielle
#### - Diffusion Séquentielle
On a deux oracles :
- Un qui vérifie que les éléments sont strictement croissants.
- Et un second qui vérifie que tous les canaux ont les mêmes éléments entre eux.
#### - Diffusion Epoque
Ici on a qu'un seul oracle qui vérifie simplement que les valeurs sont strictement dans l'ordre croissant
Ici on a qu'un seul oracle qui vérifie simplement que les valeurs sont strictement dans l'ordre croissant.

View File

@@ -10,8 +10,8 @@ public class DiffusionEpoque implements AlgoDiffusion {
public CapteurImpl capteur;
private Future<?>[] futures;
public DiffusionEpoque(CapteurImpl capteur){
this.capteur = capteur;
public DiffusionEpoque(CapteurImpl c){
this.capteur = c;
this.futures = new Future<?>[capteur.observers.size()];
}

View File

@@ -7,14 +7,14 @@ import java.util.concurrent.Future;
import interfaces.AlgoDiffusion;
import interfaces.ObserverDeCapteurAsync;
public class DiffusionSequencielle implements AlgoDiffusion {
public class DiffusionSequentielle implements AlgoDiffusion {
public CapteurImpl capteur;
private List<Future<?>> futures;
private int value;
public DiffusionSequencielle(CapteurImpl capteur){
this.capteur = capteur;
public DiffusionSequentielle(CapteurImpl c){
this.capteur = c;
this.futures = new ArrayList<Future<?>>();
}

View File

@@ -11,6 +11,7 @@ public class GetValueReq implements Callable<Integer> {
}
//AO2 - concrete MI
@Override
public Integer call() {
return capteur.getValueDiffusion();
}

View File

@@ -10,7 +10,7 @@ public class Scheduler {
this.scheduler = Executors.newScheduledThreadPool(nThread);
}
public ScheduledExecutorService getScheculer(){
public ScheduledExecutorService getScheduler(){
return this.scheduler;
}

View File

@@ -6,7 +6,7 @@ import impl.Canal;
import impl.CapteurImpl;
import impl.DiffusionAtomique;
import impl.DiffusionEpoque;
import impl.DiffusionSequencielle;
import impl.DiffusionSequentielle;
import impl.Scheduler;
@@ -19,7 +19,7 @@ public class main {
CapteurImpl c = new CapteurImpl();
DiffusionAtomique algoAtom = new DiffusionAtomique(c);
DiffusionSequencielle algoSeq = new DiffusionSequencielle(c);
DiffusionSequentielle algoSeq = new DiffusionSequentielle(c);
DiffusionEpoque algoEpoq = new DiffusionEpoque(c);
//algoEpoq.capteur = c;
@@ -32,7 +32,7 @@ public class main {
c.attach(canal);
}
ScheduledExecutorService clock = scheduler.getScheculer();
ScheduledExecutorService clock = scheduler.getScheduler();
clock.scheduleAtFixedRate(() -> c.tick(), 0, 500, TimeUnit.MILLISECONDS);
}
}

View File

@@ -58,7 +58,7 @@ public class TestAlgoDiffusionAtom {
c.attach(canal);
}
ScheduledExecutorService clock = scheduler.getScheculer();
ScheduledExecutorService clock = scheduler.getScheduler();
ScheduledFuture<?> future = clock.scheduleAtFixedRate(() -> c.tick(), 0, 500, TimeUnit.MILLISECONDS);
for(int i = TEST_TIME/6; i>0; i--){ //attend que le capteur génère des valeurs

View File

@@ -58,7 +58,7 @@ public class TestAlgoDiffusionEpoq {
DiffusionEpoque algo = new DiffusionEpoque(c);
c.setAlgoDiffusion(algo);
ScheduledExecutorService clock = scheduler.getScheculer();
ScheduledExecutorService clock = scheduler.getScheduler();
ScheduledFuture<?> future = clock.scheduleAtFixedRate(() -> c.tick(), 0, 500, TimeUnit.MILLISECONDS);
Thread.sleep(10000);

View File

@@ -13,7 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import impl.Afficheur;
import impl.Canal;
import impl.CapteurImpl;
import impl.DiffusionSequencielle;
import impl.DiffusionSequentielle;
import impl.Scheduler;
public class TestAlgoDiffusionSeq {
@@ -47,7 +47,7 @@ public class TestAlgoDiffusionSeq {
Scheduler scheduler = new Scheduler(NB_CANAUX);
CapteurImpl c = new CapteurImpl();
DiffusionSequencielle algo = new DiffusionSequencielle(c);
DiffusionSequentielle algo = new DiffusionSequentielle(c);
c.setAlgoDiffusion(algo);
for(int i = 0; i<NB_CANAUX; i++){
@@ -58,7 +58,7 @@ public class TestAlgoDiffusionSeq {
c.attach(canal);
}
ScheduledExecutorService clock = scheduler.getScheculer();
ScheduledExecutorService clock = scheduler.getScheduler();
ScheduledFuture<?> future = clock.scheduleAtFixedRate(() -> c.tick(), 0, 500, TimeUnit.MILLISECONDS);
Thread.sleep(10000);