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.

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

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);
    }
}