1 Lucidi delle esercitazioni di Sistemi di Elaborazione in Rete Università degli Studi della Calabria Corso di Laurea in Ingegneria Informatica A.A. 2003/2004
2 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 */ } }
3 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; }
4 Lettori-Scrittori con sincronizzazione Java (3) public synchronized int endRead() { readerCount- -; if (readerCount == 0) { dbReading=false; notifyAll(); } return readerCount; }
5 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(); }
6 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(); }
7 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(); }
8 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(); }
9 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.
10 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 }
11 I 5 filosofi con sincronizzazione Java (1) Supponiamo esista un tavolo con 5 piatti, 5 posti a tavola, 5 forchette ed al centro uninsalatiera 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. La forchetta a SN delli-simo filosofo è: i; La forchetta a DS delli-sima filosofo è: (i+1)%5;
12 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(); }
13 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(); }
14 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*/ }
15 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(); }
16 Il problema dello Sleeping Barber E dato un salone di barbiere, avente un certo numero di posti dattesa ed ununica 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 dattesa liberi, il cliente attende, altrimenti se ne va. Scrivere in Java un programma che risolva tale problema, simulando lattività dei diversi soggetti (il Salone, il Barbiere, i Clienti) ed evidenziandone su video lo stato. Limplementazione della soluzione deve far uso delle opportune primitive di sincronizzazione e mutua esclusione.
17 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 ( ) { … } }
18 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; }
19 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*/
20 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); }
21 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 }
22 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 (); }