Università degli Studi della Calabria Corso di Laurea in Ingegneria Informatica Lucidi delle esercitazioni di Sistemi di Elaborazione in Rete A.A. 2003/2004 1 Lettori-Scrittori con sincronizzazione Java (1) public class Database { private int readerCount; private boolean dbReading; private boolean dbWriting; public Database() { readerCount = 0; dbReading = false; dbWriting = false; } public synchronized int startRead() { /* lucidi seguenti */ } public synchronized int endRead() { /* lucidi seguenti */ } public synchronized void startWrite() { /* lucidi seguenti */ } public synchronized void endWrite() { /* lucidi seguenti */ } } 2 Lettori-Scrittori con sincronizzazione Java (2) public synchronized int startRead() { while (dbWriting == true) { try { wait(); } catch (InterruptedException e) { } } readerCount++; if (readerCount == 1) dbReading = true; return readerCount; } 3 Lettori-Scrittori con sincronizzazione Java (3) public synchronized int endRead() { readerCount- -; if (readerCount == 0) { dbReading=false; notifyAll(); } return readerCount; } 4 Lettori-Scrittori con sincronizzazione Java (4) public synchronized void startWrite() { while (dbReading == true || dbWriting == true) { try { wait(); } catch (InterruptedException e) { } } dbWriting = true; } public synchronized void endWrite() { dbWriting = false; notifyAll(); } 5 Lettori-Scrittori con sincronizzazione Java (5) public class Readers extends Thread { Database db; int id; public Readers(Database db,int id){ this.db=db; this.id=id; } public void run(){ while (true){ db.startRead(); db.endRead(); } } } 6 Lettori-Scrittori con sincronizzazione Java (6) public class Writers extends Thread { Database db; int id; public Writers(Database db,int id){ this.db=db; this.id=id; } public void run(){ while (true){ db.startWrite(); db.endWrite(); } } } 7 Lettori-Scrittori con sincronizzazione Java (7) public class TestRW { public static void main(String [ ] args){ Database db=new Database(); for (int i=0;i<10;i++){ (new Readers(db,i)).start(); (new Writers(db,i)).start(); } } 8 Blocchi sincronizzati (1) Anche blocchi di codice, oltre che interi metodi, possono essere dichiarati synchronized. Ciò consente di associare un lock la cui durata è tipicamente inferiore a quella di un intero metodo synchronized. 9 Blocchi sincronizzati (2) public void syncronized F() { // sezione non critica (p.es.: inizializzazione di variabili locali) // sezione critica // sezione non critica } public void F() { // sezione non critica synchronized (this) { // sezione critica } // sezione non critica } 10 I 5 filosofi con sincronizzazione Java (1) Supponiamo esista un tavolo con 5 piatti, 5 posti a tavola, 5 forchette ed al centro un’insalatiera di spaghetti. I filosofi seduti intorno al tavolo sanno fare solo due cose: mangiare e pensare. Il problema è che, siccome si tratta di spaghetti, il generico filosofo per servirsi ha bisogno di entrambe le forchette (quella alla sua DS e quella alla sua SN). Poi per mangare gliene serve solo una. 2 1 1 2 0 0 3 3 4 4 La forchetta a SN dell’i-simo filosofo è: i; La forchetta a DS dell’i-sima filosofo è: (i+1)%5; 11 I 5 filosofi con sincronizzazione Java (2) (senza deadlock) Public class 5Filosofi { private boolean fork[ ]={true,true,true,true,true}; public synchronized void getForks(int i) { while(!fork[i] || !fork[(i+1)%5]) try{wait(); }catch(InterruptedException e){ } fork[i]=false; fork[(i+1)%5]=false; notifyAll(); /*eventuale*/ } public synchronized void putForks(int i) { fork[i]=true; fork[(i+1)%5]=true; notifyAll(); } } 12 I 5 filosofi con sincronizzazione Java (3) (senza deadlock e senza starvation) Public class 5Filosofi { private boolean fork[ ]={true,true,true,true,true}; int cont[]={0,0,0,0,0}; public synchronized void getForks(int i) { while(!fork[i] || !fork[(i+1)%5] || (cont[i]>cont[(i+1)%5)] || (cont[i]>cont[(i+4)%5]) try{wait(); }catch(InterruptedException e){ } fork[i]=false; fork[(i+1)%5]=false; notifyAll(); /*eventuale*/ } public synchronized void putForks(int i) { fork[i]=true; fork[(i+1)%5]=true; cont[i]++; notifyAll(); } } 13 I 5 filosofi con sincronizzazione Java (4) (I Threads Filosofo) public class Filosofo extends Thread { int id; 5Filosofi cf; public Filosofo(int id, String nome, 5Filosofi cf) { super(nome); this.id=id; this.cf=cf; } public void run() { for(; ;){ cf.getForks(id); System.out.println(“Il filosofo”+id+” mangia”); try{ sleep((int)(Math.random()*5000)); catch(InterruptedException e){ } /*il filosofo sta mangiando*/ cf.putForks(id); try{ sleep((int)(Math.random()*5000));} catch(InterruptedException e){ } /*il filosofo sta pensando*/ } } } 14 I 5 filosofi con sincronizzazione Java (4) (Il main) public class Test5Filosofi { public static void main(String [] args){ 5Filosofi gestore=new 5Filosofi(); for (int i=0;i<5;i++) new Filosofo(i,”Filosofo# “+i, gestore).start(); } } 15 Il problema dello Sleeping Barber E’ dato un salone di barbiere, avente un certo numero di posti d’attesa ed un’unica poltrona di lavoro. Nel salone lavora un solo barbiere, il quale è solito addormentarsi sulla poltrona di lavoro in assenza di clienti. Arrivando nel salone, un cliente può trovare le seguenti situazioni: • Il barbiere dorme sulla poltrona di lavoro. Il cliente sveglia il barbiere e si accomoda sulla poltrona di lavoro, quindi il barbiere lo serve. • Il barbiere sta servendo un altro cliente: se ci sono posti d’attesa liberi, il cliente attende, altrimenti se ne va. Scrivere in Java un programma che risolva tale problema, simulando l’attività dei diversi soggetti (il Salone, il Barbiere, i Clienti) ed evidenziandone su video lo stato. L’implementazione della soluzione deve far uso delle opportune primitive di sincronizzazione e mutua esclusione. 16 Salone (1) public class Salone implements Runnable { int sedie,posti; Thread barbiere=null; boolean dorme,cliente; boolean fineAttesa; public Salone(int sedie){ this.sedie=sedie; posti=sedie; dorme=true; cliente=false; fineAttesa=false; barbiere=new Thread(this); barbiere.start(); } public synchronized boolean richiesta ( ) { … } public void run ( ) { … } } 17 Salone: richiesta (2) public synchronized boolean richiesta( ) { if (posti==0) return false; if ( (posti<sedie) || (!dorme)){ posti--; while(true) { try {wait();}catch(InterruptedException e){ } if (fineAttesa){ fineAttesa=false; notifyAll(); break; } } cliente=true; } else{ dorme=false; cliente=true; notify(); } while (cliente) try{wait();}catch(InterruptedException e){} return true; } 18 Salone: run (3) public void run ( ) { while (true){ synchronized(this) { if (!cliente) { if (posti==sedie) { dorme=true; while(dorme) try{wait();}catch(InterruptedException e){ } } else{posti++;fineAttesa=true; notify(); while (fineAttesa) try{wait();}catch(Interrupted…){} } /*fine synchronized*/ try{ Thread.sleep((int)(Math.random*1000));}catch(…){}; synchronized (this){ cliente=false; notifyAll(); } } } }/*fine Salone*/ 19 Cliente (1) class Cliente extends Thread { private Salone salone; private int id; public Cliente (Salone salone, int id) { this.salone = salone; this.id = id; } public void run () { while (true) { boolean servito=salone.richiesta(); if (servito) { int tempoDiRicrescita = (int)((Math.random()*3000)); System.out.println ("Il cliente "+id+" attende la ricrescita dei capelli. "+"Tempo di ricrescita = "+tempoDiRicrescita); try { sleep (tempoDiRicrescita); } catch (InterruptedException e) { System.out.println (e); } 20 Cliente (2) else{ System.out.println(“Il cliente+ id+”trova tutto pieno e va via…”); int tempoDiRiprovo= (int)((Math.random()*1000)); try { sleep (tempoDiRiprovo); } catch (InterruptedException e) { System.out.println (e); } } } // while } } 21 Il problema dello Sleeping Barber public class SleepingBarber { public static void main (String args[]) { int postiDiAttesa=5; Salone s = new Salone (postiDiAttesa); /*il barbiere è già attivo*/ for (int i = 1; i <= 10; i++) { Cliente c = new Cliente (s, i); c.start (); } } } 22