[monitor] Officina

Officina Ferrari

Ci sono nGomme gommisti che montano gomme sulle auto. I gommisti devono attendere
l’arrivo delle gomme su 2 nastri. Ogni gommista ha un id. Se l’id è pari attende
le gomme dal nastro 0 (destro) se l’id è dispari dal nastro sinistro (1).
i gommisti non si scontrano tra loro (questa sincronizzazione è già realizzata)

Si devono realizzare le seguenti sincronizzazioni

  1. i gommisti attendono la gomma sul nastro (attendiGomma)
  2. i gommisti notificano l’avvenuto prelievo della gomma (prelevataGomma)
  3. i nastri si fermano finché uno dei gommisti non preleva la gomma (gommaFineNastro)
  4. i gommisti attendono le auto (attendiAuto)
  5. i gommisti notificano l’avvenuto montaggio (gommaMontata)
  6. le auto attendono il montaggio di tutte le gomme (attendiMontaggioGomme)

Le auto si comportano come segue:

while(true) {
    // Porta le macchine senza gomme
     
    // Attende il montaggio delle gomme
    officina.attendiMontaggioGomme();
     
    // Porta via le macchine con le gomme
}

I gommisti si comportano come segue:

while(true) {
	// il gommista si sposta fino al nastro delle gomme

	// il gommista attende la gomma
	officina.attendiGomma(id);

	// il gommista rimuove la gomma dal nastro

	// il gommista notifica che ha prelevato la gomma
	officina.prelevataGomma(id);

	// il gommista si sposta fino all'auto per montare la gomma

	// il gommmista attende l'auto
	officina.attendiAuto(id);

	// il gommista notifica il montaggio della gomma
	officina.gommaMontata(id);
}

I nastri delle gomme si comportano come segue:

while(true) {

	// si muove

	// se è in fondo attende che la gomma sia prelevata
	officina.gommaFineNastro(n);
}

La verifica è disponibile qui.

Soluzione commentata del monitor Officina

public class Officina {
	/* Il numero di gomme da montare per ogni gruppo di macchine. Corrisponde al numero
	 * dei gommisti. */
	int nGomme;
	/* Vettore usato per tenere traccia se è presente una gomma alla fine di un nastro
	 * (true) o meno (false). Il vettore è di due elementi: quello di indice 0 si riferisce
	 * al nastro destro, quello di indice 1 al sinistro. */
	boolean[] fineNastro;
	/* Vettore usato per tenere traccia se un gommista ha montato la ruota (true) o meno (false). */
	boolean[] gommaMontata;
	/* Usata per modellare il fatto che le auto siano arrivate e in attesa di farsi montare le
	 * ruote (true) oppure no (false). */
	boolean macchineArrivate;

	Officina(int nGomme) {
		this.nGomme = nGomme;
		inizializza();
	}

	void inizializza() {
		/* Dal momento che Java inizializza a false le variabili booleane, è sufficiente creare
		 * i due vettori. */ 
		fineNastro = new boolean[2];
		gommaMontata = new boolean[nGomme];
	}

	public synchronized void attendiGomma(int id) throws InterruptedException {
		/* Attendi se non è presente una gomma al termine del nastro associato al gommista. */
		while (!fineNastro[id%2])
			wait();
	}

	public synchronized void prelevataGomma(int id) {
		/* Notifica che la gomma è stata raccolta dal gommista. Notare che la gomma può essere
		 * raccolta solo dal gommista che si trova davanti al nastro, quindi non è necessario
		 * verificare nuovamente che la posizione sia a true. */
		fineNastro[id%2] = false;
		notifyAll();
	} 

	public synchronized void gommaFineNastro(int n) throws InterruptedException {
		/* Notifica che è presente una ruota al termine del nastro. */
		fineNastro[n] = true;
		notifyAll();
		/* Non riattivare il nastro finché la ruota presente al termine non viene raccolta
		 * da un gommista. */
		while (fineNastro[n])
			wait();
	}

	public synchronized void attendiAuto(int id) throws InterruptedException {
		/* Attendi se le macchine non sono ancora arrivate o hai già montato la ruota. */
		while (!macchineArrivate || gommaMontata[id])
			wait();
	}

	public synchronized void gommaMontata(int id) {
		/* Notifica che il gommista ha montato la ruota che aveva precedentemente raccolto. */
		gommaMontata[id] = true;
		notifyAll();
	}

	public synchronized void attendiMontaggioGomme() throws InterruptedException {
		/* Notifica ai gommisti l'arrivo delle auto in posizione: ora possono iniziare a
		 * montare le gomme. */
		macchineArrivate = true;
		notifyAll();
		/* Verifica che tutte le gomme siano state montate. */
		for (int i = 0; i < nGomme; i++) {
			while (!gommaMontata[i])
				wait();
		}
		/* Riattiva il nastro e segna che tutte le gomme del turno successivo devono ancora
		 * essere montate. */
		macchineArrivate = false;
		for (int i = 0; i < nGomme; i++)
			gommaMontata[i] = false;
	}
}