[monitor] Gioco di squadra

Ci sono 4 squadre contrassegnate dai colori Rosso, Bianco, Verde, Blu, codificati con i numeri da 0 a 3. Ogni squadra è composta da numComponenti giocatori, identificati con in numeri da 0 a numComponenti-1.
Le squadre devono cercare di entrare in una porta prima delle altre seguendo le regole seguenti:

  • nessun giocatore deve entrare prima che la porta sia stata aperta dal thread principale (main) tramite l’invocazione del metodo porta.apri(). A tale scopo i thread invocano il metodo porta.attendi();
  • solo il capitano della squadra (giocatore con id 0) compete con gli altri capitani per l’accesso alla porta ( metodo porta.entra(...) );
  • quando un capitano riesce ad entrare tutti i giocatori della sua squadra possono entrare ( sempre metodo porta.entra(...) ) ma devono entrare in fila: 1,2,3, ... , numComponenti-1
  • mentre una squadra entra le altre squadre attendono. Solo quando tutta la squadra è entrata i capitani possono di nuovo competere per la porta.

L’output atteso dovrebbe essere il seguente: Tutti i giocatori vengono creati e stampano a video che sono pronti (notare che una sleep ‘mescola’ l’ordine dei giocatori). Quando la porta viene aperta, le varie squadre entrano nella porta una alla volta. Ad esempio:

La porta e' aperta!!
Componente Blu numero 0 e' entrato!
Componente Blu numero 1 e' entrato!
Componente Blu numero 2 e' entrato!
Componente Blu numero 3 e' entrato!
Componente Blu numero 4 e' entrato!
Componente Blu numero 5 e' entrato!
Componente Blu numero 6 e' entrato!
Componente Blu numero 7 e' entrato!
Componente Blu numero 8 e' entrato!
Componente Blu numero 9 e' entrato!
Componente Rosso numero 0 e' entrato!
Componente Rosso numero 1 e' entrato!
Componente Rosso numero 2 e' entrato!
Componente Rosso numero 3 e' entrato!
Componente Rosso numero 4 e' entrato!
Componente Rosso numero 5 e' entrato!
Componente Rosso numero 6 e' entrato!
Componente Rosso numero 7 e' entrato!
Componente Rosso numero 8 e' entrato!
Componente Rosso numero 9 e' entrato!
Componente Verde numero 0 e' entrato!
Componente Verde numero 1 e' entrato!
...

L’ordine dei colori varia da un’esecuzione all’altra in quanto dipende da quale capitano è più veloce.

Scopo della esercitazione è implementare il monitor ‘Porta’ con i tre metodi sopra descritti. Utilizzare il seguente programma di test:

import java.lang.Math;

public class Test extends Thread {
  private static final String colori[]={"Rosso","Bianco","Verde","Blu"}; // colori
  private static final int numColori = colori.length; // quanti colori/squadre ci sono
  private static final int numComponenti =10; // numero componenti
  private final int col, num; // colore e numero del giocatore
  private final Porta porta; // monitor utlizzato dal giocatore
  
  // costruttore: salva colore numero e monitor
  Test(int col,int num, Porta porta) {
    this.col = col;
    this.num = num;
    this.porta = porta;
  }
  
  // lancia il codice vero e proprio e cattura l'eccezione di interruzione
  public void run() {
    try {
      code();
    } catch (InterruptedException e) {
      System.out.println("Componente "+colori[col]+" numero "+num+" interrotto!!");
    }
  }
  
  // codice dei thread
  void code() throws InterruptedException {
    // evita che i thread siano gia' in fila
    sleep((int)(1000*Math.random()));
    
    // il giocatore e' pronto
    System.out.println("Componente "+colori[col]+" numero "+num+" pronto!");
    
    // attende che la porta venga aperta dal main
    porta.attendi();
    
    // cerca di entrare
    porta.entra(col,num);
    
    // attenzione che questo output non e' sincronizzato con entra.... quindi non e' detto
    // che venga stampato nell'ordine corretto. Aggiungere un blocco synchonized(porta){ } 
    // se necessario
    System.out.println("Componente "+colori[col]+" numero "+num+" e' entrato!");
    
  }
  
  public static void main(String argv []) throws InterruptedException {
    int i,j;
    
    Porta p = new Porta(numComponenti); // crea il monitor
    
    // crea i thread dei vari colori/numeri
    for (i=0; i<numColori; i++)
      for (j=0; j<numComponenti; j++) {
        (new Test(i,j,p)).start();
      }
  
    // attende 3 secondi prima di aprire la porta (tutti i thread devono attendere)
    sleep(3000);
    p.apri();
    System.out.println("La porta e' aperta!!");
  }
  
}