From ebfb7504a12de26ae9a31cc39445686e03bb3a91 Mon Sep 17 00:00:00 2001 From: elleguehen Date: Wed, 25 Jan 2023 15:04:46 +0100 Subject: [PATCH] =?UTF-8?q?Rendu=20apr=C3=A8s=20partie=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rendu/rendu.md | 184 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 173 insertions(+), 11 deletions(-) diff --git a/rendu/rendu.md b/rendu/rendu.md index 95e55da..86b5d3b 100644 --- a/rendu/rendu.md +++ b/rendu/rendu.md @@ -5,7 +5,7 @@ Elliott LE GUEHENNEC -- Yorick GEOFFRE ## 1. Simulation d'une patisserie ### A. -Le patron lecteur/rédacteur présente le problème plusieurs lecteurs peuvent lire la même donnée, et ne peuvent pas la modifier; alors que les pâtisseries appartiennent au seul client qui les consommera (et donc les modifiera). +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. @@ -16,17 +16,140 @@ La `Boulangerie` est donc le moniteur dans ce modèle, on l'utilise pour synchro 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. -Le code de cette classe est en bas de ce document +## 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();`. -## Annexes +## 3. Fin de programme + + + +## Code -### Le ThreadWeaver ```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 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 sweets = new ArrayBlockingQueue(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 runners = new ArrayList(); private final List managed = new ArrayList(); - public void addRunners(Runnable... runners){ - + public void addRunners(Runnable... addedRunners){ + runners.addAll(Arrays.stream(addedRunners).toList()); } public void weave(){ @@ -44,7 +167,7 @@ public class ThreadWeaver { public void recover(){ for(Thread t : managed){ try { - t.wait(); + t.join(); }catch(InterruptedException ie){ System.out.println(ie.getMessage()); } @@ -55,22 +178,61 @@ public class ThreadWeaver { public void recover(Long timeout){ for(Thread t : managed){ try { - t.wait(timeout); + t.join(timeout); }catch(InterruptedException ie){ System.out.println(ie.getMessage()); } - managed.remove(t); } termina(); } public void termina(){ for(Thread t : managed){ - System.out.println("Thread "+t.getName()+" has not stopped being cleaned up"); - t.interrupt(); + 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); + } +} ``` \ No newline at end of file