[monitor] piscina

Oggi si nuota! La verifica consiste nell’implementare un monitor per la sincronizzare dei thread che rappresentano i nuotatori di diverse squadre e lo starter della gara. La competizione si svolge su una piscina suddivisa in corsie, ciascuna delle quali è occupata ad una squadra. Lo starter dà il via quando il primo nuotatore di ogni squadra è schierato sulla griglia di partenza. Ogni nuotatore deve fare due vasche prima di lasciare il posto al nuotatore successivo della propria squadra.

Dovete implementare i seguenti metodi della classe Piscina.java contenuta nel file ZIP:

  • void chiediMutex(int x, int y): chiede il mutex per accedere alla posizione (x, y). Viene invocato dai nuotatori prima di eseguire lo spostamento.
  • void rilasciaMutex(int x, int y): rilascia il mutex in posizione (x, y). Viene invocato dai nuotatori quando abbandonano la posizione (x, y).
  • void attendiPartenza(int corsia): il nuotatore è schierato in bordo vasca e deve attendere il momento in cui può partire.
  • void arrivato(int corsia): il nuotatore ha terminato le due vasche, il successivo può partire.
  • void attendiSchieramento(): viene invocato dallo starter per attendere che tutti i (primi) nuotatori siano schierati.
  • void daiVia(): a schieramento completato, lo starter dà inizio alla gara.

Un nuotatore esegue le seguenti operazioni:

  • raggiunge il bordo vasca (usando chiediMutex e rilasciaMutex);
  • attende di potersi tuffare (invocando attendiPartenza);
  • si tuffa e fa le 2 vasche (usando chiediMutex e rilasciaMutex);
  • notifica che è arrivato (tramite la funzione arrivato);
  • esce dalla vasca e si posiziona all’esterno (usando chiediMutex e rilasciaMutex).

Lo starter attende che i nuotatori si siano schierati (usando attendiSchieramento) e dà il via alla gara (usando daiVia).

Visualizza la soluzione

/*
 * La verifica consiste nell'implementazione di un monitor che permetta lo svolgersi di una gara di nuoto in cui:
 * - due nuotatori non possano occupare contemporaneamente la medesima posizione dello schema (costituito dalla
 *   piscina e la zona esterna sulla sinistra);
 * - lo starter deve consentire l'inizio della gara solo quando tutti i nuotatori siano schierati;
 * - i nuotatori della batteria iniziale devono attendere l'inizio della gara, dichiarato dallo starter;
 * - ogni nuotatore deve attendere che il precedente abbia terminato le due vasche prima di tuffarsi a sua volta.
 * 
 * Per realizzare la sincronizzazione desiderata, sono usate le seguenti strutture dati:
 * - 'schema': matrice in cui ogni posizione indica se la corrispondente cella dello schema è occupata da un
 *   nuotatore ('true' rappresenta una cella occupata, 'false' una cella libera);
 * - 'schierato': vettore che indica se un nuotatore è schierato nella corrispondente corsia (usato per la
 *   fase iniziale);
 * - 'partenza': vettore che indica se il corrispondente nuotatore può tuffarsi. Il vettore è usato sia
 *   all'avvio della gara (quando sarà modificato dallo starter), sia per gestire il succedersi dei nuotatori
 *   (quando verrà modificato dal nuotatore precedente nella corsia).
 */
public class Piscina {
	private int x, y, corsie;
	private boolean[] schierato;
	private boolean[] partenza;
	private boolean[][] schema; 

	public Piscina(int x, int y, int corsie) {
		this.x = x;
		this.y = y;
		this.corsie = corsie;

		/* NB. Da specifica del linguaggio Java, tutte le variabili booleane sono inizializzate a 'false'
		 * di default. */
		schema = new boolean[x][y];
		schierato = new boolean[corsie];
		partenza = new boolean[corsie];
	}

	public synchronized void chiediMutex(int x, int y) throws InterruptedException {
		/* Attendi finché la cella non si libera. */
		while (schema[x][y]) {
			wait();
		}
		/* Segnala la cella come occupata. */
		schema[x][y] = true;
	}

	public synchronized void rilasciaMutex(int x, int y) {
		/* Libera la cella e notifica eventuali nuotatori in attesa. */
		schema[x][y] = false;
		notifyAll();
	}

	public synchronized void attendiPartenza(int corsia) throws InterruptedException {
		/* Il nuotatore è schierato: notifica lo starter. Questa parte viene eseguita da parte di ogni nuotatore,
		 * ma non è rilevante per quelli che non fanno parte del gruppo iniziale. */
		schierato[corsia] = true;
		notifyAll();

		/* Attendi il permesso di partire da parte dello starter o dal nuotatore precedente. */
		while (!partenza[corsia]) {
			wait();
		}
		/* Impedisci la partenza al nuotatore successivo. */
		partenza[corsia] = false;
	}

	public synchronized void arrivato(int corsia) {
		/* Il nuotatore ha terminato le vasche: notifica la possibilità di partire al successivo. */
		partenza[corsia] = true;
		notifyAll();
	}

	public synchronized void attendiSchieramento() throws InterruptedException {
		/* Attendi fino a che tutti i nuotatori non sono schierati. */
		for (int i = 0; i < corsie; i++) {
			while (!schierato[i]) {
				wait();
			}
		}
	}

	public synchronized void daiVia() {
		/* Notifica a tutti i nuotatori schierati di partire. */
		for (int i = 0; i < corsie; i++) {
			partenza[i] = true;
		}
		notifyAll();
	}
}

One thought on “[monitor] piscina”

  1. Si poteva risolvere il via dello starter con un contatore “partenza” inizializzato a zero, in questo modo:

    public synchronized void attendiPartenza(int corsia) throws InterruptedException {
    partenza++;
    notifyAll();
    while(!attesa[corsia]){
    wait();
    }
    attesa[corsia]=false;
    }

    public synchronized void attendiSchieramento() throws InterruptedException {
    while(partenza<corsie){
    wait();
    }
    }

    public synchronized void daiVia() {
    for(int i=0;i<corsie;i++){
    partenza[i]=true;
    }
    notifyAll();
    }
    }

Comments are closed.