You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
6.6 KiB
238 lines
6.6 KiB
# TP2 - Système
|
|
|
|
Elliott LE GUEHENNEC -- Yorick GEOFFRE
|
|
|
|
## 1. Simulation d'une patisserie
|
|
|
|
### A.
|
|
Le patron lecteur/rédacteur présente le problème suivant : lorsqu'un lecteur lit la ressource, il la bloque et les rédacteurs ne peuvent pas la modifier. Or, dans notre configuration, il se peut que le `Client` doive attendre alors qu'il essaie d'obtenir sa `Patisserie`, mais il serait quand même en train de lire la file d'attente, empêchant ainsi le `Patissier` de réapprovisioner la file; c'est un deadlock.
|
|
|
|
### B.
|
|
L'exclusion mutuelle se produit lorsqu'un `Client` veut acheter une `Patisserie` alors qu'aucune n'est disponible. Lorsque cela se produit, la `Boulangerie` bloque le thread en attendant qu'un `Patissier` dépose une `Patisserie` dans la boulangerie, débloquant ainsi la demande du client. La `Boulangerie` débloque le thread correspondant et retourne la `Patisserie` désirée au client.
|
|
|
|

|
|
|
|
La `Boulangerie` est donc le moniteur dans ce modèle, on l'utilise pour synchroniser toutes les opérations des `Client`, des `Patissier`, et la file d'attente.
|
|
|
|
Pour lancer des threads, on a créé une class ThreadWeaver. On peut lui faire passer des `Runnable` avec `addRunners()`, puis on leur assigne un thread chacun avec `weave()`, avant de les lancer avec `run()`. Avec `recover()`, on attend que tous les threads se soient terminés, et avec `termina()`, on interrompt tous les threads restants en affichant une erreur.
|
|
|
|
## 2. Simulation d'une patisserie avec collection ThreadSafe
|
|
Ici, la `ArrayBlockingQueue` devient le moniteur, car elle gère elle-même l'accès par exclusion mutuelle. Le client sera bloqué par la file, et attendra tant qu'il n'aura pas son code grâce à `ArrayBlockingQueue.take();`.
|
|
|
|
## 3. Fin de programme
|
|
|
|
|
|
|
|
## Code
|
|
|
|
```java
|
|
public class Patisserie {
|
|
|
|
public Patisserie() {
|
|
}
|
|
}
|
|
|
|
public class Gateau extends Patisserie {
|
|
|
|
public Gateau() {
|
|
}
|
|
|
|
}
|
|
|
|
public class Client implements Runnable {
|
|
protected final Boulangerie local;
|
|
|
|
public Client(Boulangerie b) {
|
|
local = b;
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
while(true) {
|
|
local.achete();
|
|
System.out.println("J'ai acheté ma patisserie");
|
|
try {
|
|
Thread.sleep(80);
|
|
} catch (InterruptedException e) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class LimitedClient extends Client{
|
|
public LimitedClient(Boulangerie b) {
|
|
super(b);
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
while(true) {
|
|
local.achete();
|
|
System.out.println("J'ai acheté ma patisserie - Limited");
|
|
try {
|
|
Thread.sleep(80);
|
|
} catch (InterruptedException e) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class Patissier implements Runnable {
|
|
public AtomicBoolean shouldRun = new AtomicBoolean(true);
|
|
private final Boulangerie local;
|
|
|
|
public Patissier(Boulangerie b) {
|
|
local = b;
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
while(shouldRun.get()) {
|
|
local.depose(new Patisserie());
|
|
System.out.println("J'ai produit ma patisserie");
|
|
try {
|
|
Thread.sleep(100);
|
|
} catch (InterruptedException e) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class Boulangerie {
|
|
private final ArrayList<Patisserie> sweets = new ArrayList<>();
|
|
|
|
public synchronized void depose(Patisserie p) {
|
|
this.notify();
|
|
sweets.add(p);
|
|
}
|
|
|
|
public synchronized Patisserie achete() {
|
|
while(sweets.size() == 0) {
|
|
try {this.wait();} catch (InterruptedException ignored) {}}
|
|
Patisserie pat = sweets.get(0);
|
|
sweets.remove(pat);
|
|
return pat;
|
|
}
|
|
|
|
public void getStock() {
|
|
// TODO implement here
|
|
}
|
|
|
|
}
|
|
|
|
public class BoulangerieThreadSafe extends Boulangerie{
|
|
private final BlockingQueue<Patisserie> sweets = new ArrayBlockingQueue<Patisserie>(50);
|
|
|
|
@Override
|
|
public void depose(Patisserie p) {
|
|
try{
|
|
sweets.put(p);
|
|
}catch(InterruptedException ignored){}
|
|
}
|
|
|
|
@Override
|
|
public Patisserie achete() {
|
|
try{return sweets.take();} catch (InterruptedException e) {}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void getStock() {
|
|
// TODO implement here
|
|
}
|
|
}
|
|
|
|
public class ThreadWeaver {
|
|
private final List<Runnable> runners = new ArrayList<Runnable>();
|
|
private final List<Thread> managed = new ArrayList<Thread>();
|
|
public void addRunners(Runnable... addedRunners){
|
|
runners.addAll(Arrays.stream(addedRunners).toList());
|
|
}
|
|
|
|
public void weave(){
|
|
for(Runnable r: runners){
|
|
managed.add(new Thread(r));
|
|
}
|
|
}
|
|
|
|
public void run(){
|
|
for(Thread t : managed){
|
|
t.start();
|
|
}
|
|
}
|
|
|
|
public void recover(){
|
|
for(Thread t : managed){
|
|
try {
|
|
t.join();
|
|
}catch(InterruptedException ie){
|
|
System.out.println(ie.getMessage());
|
|
}
|
|
}
|
|
termina();
|
|
}
|
|
|
|
public void recover(Long timeout){
|
|
for(Thread t : managed){
|
|
try {
|
|
t.join(timeout);
|
|
}catch(InterruptedException ie){
|
|
System.out.println(ie.getMessage());
|
|
}
|
|
}
|
|
termina();
|
|
}
|
|
|
|
public void termina(){
|
|
for(Thread t : managed){
|
|
if(t.isAlive()) {
|
|
System.out.println("Thread " + t.getName() + " has not stopped being cleaned up");
|
|
t.interrupt();
|
|
}
|
|
}
|
|
managed.clear();
|
|
runners.clear();
|
|
}
|
|
}
|
|
|
|
public class Main {
|
|
public static void main(String[] args) {
|
|
ThreadWeaver tw = new ThreadWeaver();
|
|
Boulangerie b = new Boulangerie();
|
|
Patissier p = new Patissier(b);
|
|
tw.addRunners(p, new Client(b));
|
|
tw.weave();
|
|
tw.run();
|
|
|
|
try{
|
|
Thread.sleep(2000);
|
|
} catch (InterruptedException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
p.shouldRun.set(false);
|
|
tw.recover(100L);
|
|
}
|
|
}
|
|
|
|
public class Main2 {
|
|
public static void main(String[] args) {
|
|
ThreadWeaver tw = new ThreadWeaver();
|
|
Boulangerie b = new BoulangerieThreadSafe();
|
|
Patissier p = new Patissier(b);
|
|
tw.addRunners(p, new Client(b));
|
|
tw.weave();
|
|
tw.run();
|
|
|
|
try{
|
|
Thread.sleep(2000);
|
|
} catch (InterruptedException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
p.shouldRun.set(false);
|
|
tw.recover(100L);
|
|
}
|
|
}
|
|
``` |