Si deve gestire la sincronizzazione di N_AUTO che attraversano un incrocio regolato da un semaforo. Il semaforo ha 4 stati: rosso da entrambi i lati, verde in “verticale”, rosso da entrambi i lati, verde in “orizzontale”. Le auto non devono passare con il rosso e scontrarsi. Si comportano secondo il seguente schema:
finché sulla strada:
Se al semaforo:
incrocio.semaforo(direzione); // direzione=true o false a seconda se orizzontale o verticale
// muove la macchina c da (x,y) a (x+dx,y+dy)
// la macchina si muove solo se la strada e' libera
incrocio.muovi(c,x,y,dx,dy);
x+=dx; y+=dy;
incrocio.libera(x,y); // esce e libera (x,y)
Ecco un esempio di situazione con semaforo verde in verticale e rosso in orizzontale:
| V |
| |
| |
| |
| |
| |
| V |
| |
--------------------- o V o ---------------------
V < < < <
> > > > V ^
--------------------- o ^ o ---------------------
| |
| V |
| |
| |
| |
| |
| |
| |
Progettare un monitor Incrocio che implementi i seguenti metodi:
void muovi(char c, int x, int y, int dx, int dy)
se la posizionex+dx,y+dyè occupata attende. Altrimenti scrivecin tale posizione e libera
la posizione attualex,yinvocandolibera(x,y)void libera(int x, int y)
libera la posizionex,yscrivendo uno spazio (viene invocata quando le auto escono dall’incrocio)void semaforo(Boolean d)
è il semaforo nell’incrocio. viene invocato con un booleano che indica la direzione
(orizzontale o verticale). Il semaforo può essere verde in una direzione o rosso per entrambe
se il semaforo e’ rosso per la direzionedla macchina attendevoid cambiaSemaforo()
viene invocata periodicamente e cambia lo stato del semaforo. Il semaforo deve ‘ciclare’ tra
quattro stati: rosso per tutti, verde in una direzione, rosso per tutti, verde nell’altra direzione
Scaricare il file zip, modificare Incrocio.java e compilare e eseguire Automobile.java.
Visualizza la soluzione
/*
* La verifica consiste nell'implementazione di un monitor per regolare il
* movimento delle macchine nei pressi di un incrocio. In particolare, si deve:
* - sincronizzare il movimento delle macchine in modo da evitare il
* verificarsi di tamponamenti;
* - impedire l'attraversamento dell'incrocio se il semaforo è rosso.
* Per implementare le operazioni richieste, il monitor usa le seguenti
* variabili:
* - una matrice di caratteri di dimensione pari all'incrocio, dove ogni cella
* contiene uno spazio se la corrispondente posizione è libera, altrimenti
* contiene un simbolo che rappresenta la macchina che sta occupando la
* corrispondente posizione dell'incrocio;
* - un intero che codifica lo stato del semaforo: i valori 0 e 2 codificano il
* semaforo rosso in entrambe le direzioni, il valore 1 codifica il verde per
* le macchine che si muovono in verticale, il valore 3 codifica il verde per
* le macchine che si muovono in orizzonatale; questa scelta dei valori
* permette di implementare l'operazione di cambio di stato del semaforo con
* un semplice incremento modulo 4.
*/
public class Incrocio {
private char[][] strada;
private int semaforo;
public Incrocio(int DIM) {
/* Alloca una matrice di caratteri per rappresentare lo stato
* dell'incrocio e inizializzala con tutte le posizioni libere. */
this.strada = new char[DIM][DIM];
for (int i=0; i<DIM; i++) {
for (int j=0; j<DIM; j++) {
strada[i][j] = ' ';
}
}
/* Inizialmente il semaforo è rosso in tutte le direzioni
* (successivamente diventa verde quello in direzione verticale,
* quindi usiamo il valore 0 e non il 2). */
this.semaforo = 0;
}
public synchronized void muovi(char c, int x, int y, int dx, int dy) throws InterruptedException {
/* Attendi se la posizione in cui si deve spostare la macchina è
* occupata, in modo da evitare tamponamenti. */
while (strada[x+dx][y+dy] != ' ') {
wait();
}
/* Occupa la posizione e libera quella precedentemente occupata. */
strada[x+dx][y+dy]= c;
libera(x,y);
}
public synchronized void libera(int x, int y) {
/* Ora la posizione è libera. */
strada[x][y] = ' ';
/* Notifica il cambiamento alle altre macchine: se una di queste stava
* attendendo la liberazione della posizione (x, y), ora può riprovare
* ad occuparla. */
notifyAll();
}
public char strada(int x, int y) {
return strada[x][y];
}
public synchronized void semaforo(Boolean d) throws InterruptedException {
/* Attendi se il semaforo relativo alla mia direzione di marcia è rosso.
* La variabile 'd' è 'true' se la direzione di spostamento è verticale,
* 'false' se orizzontale. */
while ((d && semaforo != 1) || (!d && semaforo !=3)) {
wait();
}
}
public synchronized void cambiaSemaforo() {
/* Cambia lo stato del semaforo, come descritto sopra. */
semaforo = (semaforo + 1) % 4;
/* Notifica il cambiamento alle altre macchine: se una macchina era
* in attesa del verde, ora può avere la possibilità di muoversi.
* Come piccola ottimizzazione, evitiamo la notifica nel caso il
* semaforo diventi rosso in tutte le direzioni, in quanto nessuna
* macchina ferma al semaforo potrà muoversi. */
if (semaforo % 2 != 0) {
notifyAll();
}
}
}