Conto corrente Nella famiglia Giambietti non ci sono
Conto corrente Nella famiglia Giambietti non ci sono grossi problemi economici. Infatti il padre, Enea, di professione artista free-lance, ogni tanto riesce a vendere un’opera e rimpinguare così il conto. Gli altri membri della famiglia, cioè la moglie Luisa ed il figlio Taddeo si limitano a spendere, usando il proprio bancomat, tutto quello che trovano sul conto. A proposito, il conto non può andare in rosso. Si implementino in Java 3 processi che simulano la famiglia Giambietti. Concorrenza 1
public class Conto { private int saldo; Conto() { saldo = 10; } public synchronized void deposita(int x) { saldo += x; } public synchronized boolean ritira(int x) { if (saldo < x) return false; else { saldo -= x; return true; } } } Concorrenza 2
public class Cons extends Thread { Conto il. Suo. Conto; int max. Spesa; int tempo; Cons(int m, int t, Conto c) { il. Suo. Conto = c; max. Spesa = m; tempo = t; } public void run () { while (true) { if(!il. Suo. Conto. ritira((int)(Math. random()*max. Spesa))) System. out. println("Non riesco a tirar fuori i soldi!"); else System. out. println("Riesco a tirar fuori i soldi!"); try { sleep(tempo); } catch(Interrupted. Exception ie) { System. out. println(“ERRORE!"); } } Concorrenza 3
public class Marito extends Thread { private Conto il. Mio. Conto; Marito(Conto c) { il. Mio. Conto = c; } public void run() { while (true) { il. Mio. Conto. deposita((int)(Math. random()*1000)); try { sleep(6000); } catch(Interrupted. Exception ie) { System. out. println(“ERRORE!"); } } Concorrenza 4
public class Famiglia { public static void main(String Args[]) { Conto c = new Conto(); Marito p = new Marito(c); Cons m = new Cons(1000, 4000, c); Cons f = new Cons(300, 3000, c); p. start(); m. start(); f. start(); } } Concorrenza 5
Esercizio Thread Pentola • Dei campeggiatori mangiano servendosi da una pentola comune. • La pentola può contenere P porzioni di cibo (con P non necessariamente maggiore del numero di campeggiatori). Ogni campeggiatore mangia una porzione per volta. Quando la pentola si svuota (e solo allora), il cuoco provvede a riempirla con nuove P porzioni. • Tratteggiare in Java per le sole parti relative alla sincronizzazione tra i processi, i programmi che realizzano i comportamenti dei campeggiatori e del cuoco e la gestione della pentola.
Soluzione Class Pentola { final int P = 40; private int n. Porzioni; public Pentola() { n. Porzioni = P; }
public syncronized void prendi. Porzione(){ while ( ! (n. Porzioni > 0) ) try { wait(); } catch (Interrupted. Exception e ) { System. out. println(“ERRORE!!!!"); } n. Porzioni--; System. out. println("Pentola: presa porzione"); notify. All(); } public syncronized void riempi. Pentola(){ while ( ! (n. Porzioni == 0) ) try { wait(); } catch (Interrupted. Exception e ) { System. out. println(“ERRORE!!!!"); } n. Porzioni = P; System. out. println("Pentola: riempita di porzioni"); notify. All(); } }
Class Cuoco extends Thread{ private Pentola pentola; public Cuoco(Pentola p) { pentola=p; } public void run (){ while(true){ pentola. riempi. Pentola(); System. out. println(“cuoco: ho riempito la pentola”); } } }
Class Campeggiatore extends Thread{ private Pentola pentola; public Campeggiatore(Pentola p) { pentola=p; } public void run (){ while(true){ pentola. prendi. Porzione(); System. out. println(“Campeggiatore: ” + “ ho preso una porzione”); } } }
Class Test { public static void main(String[] args) { Pentola p=new Pentola(); Cuoco c=new. Cuoco(p) Campeggiatore c 1=new Campeggiatore(p); Campeggiatore c 2=new Campeggiatore(p); Campeggiatore c 3=new Campeggiatore(p); c. start(); c 1. start(); c 2. start(); c 3. start(); } }
Esercizio • Si consideri il sistema mostrato in figura. Il modulo PI esegue ripetutamente le seguenti operazioni: legge da tastiera una coppia di valori <i, ch>, dove i è un numero tra 0 e 3, ch un carattere, e inserisce il carattere ch nel buffer i (ognuno dei quattro buffer contiene al più un carattere). Il modulo PO considera a turno in modo circolare i quattro buffer e preleva il carattere in esso contenuto, scrivendo in uscita la coppia di valori <i, ch> se ha appena prelevato il carattere ch dal buffer i. L’accesso a ognuno dei buffer è in mutua esclusione; PI rimane bloccato se il buffer a cui accede è pieno, PO se è vuoto. Concorrenza 12
Parte 1 • Data la seguente sequenza di valori letta da PI, scrivere la sequenza scritta in corrispondenza da PO. <1, c> <0, b> <2, m> <0, f> <1, h> <3, n> Concorrenza 13
Soluzione 1 <0, b> <1, c> <2, m> <3, n> <0, f> <1, h> Concorrenza 14
Parte 2 • Descrivere brevemente in quali casi si può verificare una situazione di deadlock tra PI e PO. Illustrare con un semplice esempio. Concorrenza 15
Soluzione 2 • Deadlock: <1, a> <1, b> Concorrenza 16
Parte 3 • Implementare il sistema descritto in Java Concorrenza 17
Soluzione 3 //riceve l’input via linea di comando, es. ” 0: a 1: b 2: c” public class Buf { private char q; private boolean full; Buf() { full = false; } Concorrenza 18
public synchronized void put (char item) { while (full) try { wait(); } catch (Interrupted. Exception e) { } q = item; full = true; notify(); } public synchronized char get () { while (!full) try { wait(); } catch (Interrupted. Exception e) { } full = false; notify(); return q; } } Concorrenza 19
public class Pi extends Thread { private Buf[] buff; private String[] commands; Pi (Buf[] b, String[] c) { buff = b; commands = c; } public void run() { for(int i=0; i < commands. length; i++) buff[(int)commands[i]. char. At(0)(int)'0']. put(commands[i]. char. At(2)); } } Concorrenza 20
public class Po extends Thread { private Buf[] buff; Po (Buf[] b) { buff = b; } public void run() { while(true) { for(int i=0; i < buff. length; i++) System. out. println("Buff "+i+": "+buff[i]. get()); } } } Concorrenza 21
public class pi_po { public static void main (String [] args){ Buf[] bfs = new Buf[4]; bfs[0] = new Buf(); bfs[1] = new Buf(); bfs[2] = new Buf(); bfs[3] = new Buf(); Pi pi = new Pi(bfs, args); Po po = new Po(bfs); pi. start(); po. start(); } } Concorrenza 22
Un impianto con valvola • Un impianto può portarsi dallo stato di funzionamento normale N in uno stato di gestione di malfunzionamento M. Entrato in tale stato, entro 5 s deve essere aperta una valvola di scarico. Se non si apre, l'impiano passa ad uno stato di fermo (F). Se la valvola viene aperta, essa rimane in tale stato per un tempo non inferiore a 20 s e non superiore a 30 s, poi l’impianto ritorna nello stato N. Concorrenza 23
Impianto in Java public class Impianto extends Thread{ private int stato; // 1 = N, -1 = M, 0 = F private Valvola valvola; public Impianto(){ stato=1; } public void run(){ while (stato != 0){ System. out. println("sto lavorando!"); while (Math. random()<. 8){ // affidabilita` System. out. println("tutto bene!"); } valvola=new Valvola("Valvola Di Sfogo"); stato=-1; valvola. start(); … Concorrenza 24
… try{ System. out. println("Aspetto la valvola di sfogo!"); synchronized (valvola) { valvola. wait(5000); } } catch (Interrupted. Exception ie){ ie. print. Stack. Trace(); } System. out. println("Controllo che la valvola si sia aperta!"); if (valvola. get. Stato() == 0) { System. out. println("DISASTRO! La valvola non si e' aperta!"); stato=0; } else try{ System. out. println("La valvola si e' aperta, aspetto che finisca di sfogarsi!"); valvola. join(); }catch(Interrupted. Exception ie){ie. print. Stack. Trace(); }}} Concorrenza … 25
… public static void main(String [] args){ Impianto imp=new Impianto(); imp. start(); } } E ora la valvola: public class Valvola extends Thread{ private String name; private int stato; // 0 chiuso, 1 aperto public Valvola(String name){ this. name=name; this. stato = 0; } … Concorrenza 26
… public void run(){ … public int get. Stato() { long t = 0; return stato; } System. out. println("sono la "+name); } try{ t = (long)(5500*Math. random()); sleep(t); } catch (Interrupted. Exception ie) {ie. print. Stack. Trace(); } System. out. println(name + ": c'ho messo " + t + "ms"); stato = 1; synchronized (this) {notify(); } try{ System. out. println("Ora mi sfogo!!!"); t = (long)(20000+10000*Math. random()); sleep(t); } catch (Interrupted. Exception ie) {ie. print. Stack. Trace(); } System. out. println(name + ": mi sono sfogata per " + t + "ms"); stato = 0; } … Concorrenza 27
Esempio Si definiscano due tipi di thread: - il tipo "a", che conta da 1 a 5, aspettando 0. 2 s ad ogni passo; segnala la fine del primo conteggio; dunque riprende a contare da 5 a 1, aspettando sempre 0. 2 s ad ogni passo, per poi terminare. - il tipo "b", che alla creazione si mette in attesa di un segnale da un thread, fornito alla creazione dell'oggetto, poi termina. Si construisca dunque un programma che crei e faccia partire due thread X e Y, rispettivamente di tipo "a" e di tipo "b". Y deve mettersi in attesa di X. Concorrenza 28
public class es { public static void main (String [] args){ a x = new a("X"); b y = new b("Y", (Thread)x); x. start(); y. start(); System. out. println("Fine!"); } } Concorrenza 29
public class a extends Thread{ private String name; public a(String n) { this. name = n; } public void run() { System. out. println("sono "+name); for(int i=1; i<=5; i++) { System. out. println(name + ": " + i); try { sleep(200); } catch (Interrupted. Exception ie) { System. out. println(name+" interrotto"); } } synchronized (this) { notify(); } for(int i=5; i>=1; i--) { System. out. println(name + ": " + i); try { sleep(200); } catch (Interrupted. Exception ie) { System. out. println(name+" interrotto"); } } Concorrenza 30
public class b extends Thread{ String name; Thread attendo; public b(String n, Thread a) { this. name = n; this. attendo = a; } public void run() { System. out. println("sono "+name); System. out. println(name+": attendo. . . "); try { synchronized (attendo) { attendo. wait(); } } catch (Interrupted. Exception ie) { System. out. println(name+" interrotto"); } System. out. println(name+": ok!"); } } Concorrenza 31
Esercizio • Due autori devono lavorare sullo stesso documento, il documento è formato da diverse parti e ogni autore può prendere il lock su al massimo 2 parti del documento e due autori non possono prendere il lock sulla stessa parte. Si descriva tale problema di concorrenza in java. Concorrenza 32
public class Section { private boolean busy; public synchronized boolean get. Section(){ if (busy) { return false; } else { busy = true; return true; } } public synchronized void release. Section() { busy = false; } } Concorrenza 33
public class Author extends Thread{ int num. Sections; Sections[10]; get. Section(int n) { if(num. Sections<2) if(Sections[n]. get. Section(this)) { num. Sections++; } } Concorrenza 34
release. Section(int n) { Sections[n]. release. Section(); Num. Sections--; } public void run () { while (true) { ……… } } } Concorrenza 35
Esercizio • Si consideri un software condiviso da 10 utenti di cui si hanno a disposizione solo 4 licenze. Ciascun utente qualora desideri utilizzare il software richiede la licenza, se essa è disponibile la acquisisce, per al più 2 ore, se non è disponibile, si mette in attesa che si liberi una licenza. • Tracciare in Java le linee principali di un programma che gestisce il problema descritto sopra. Concorrenza 36
public class Manager. Licenze { private int num_disp; public Manager. Licenze(){ num_disp = 4; } Concorrenza 37
public synchronized boolean richiedi. Licenza(long minuti){ if(minuti>120) return false; //ci mettiamo in attesa finchè non c'è una licenza disponibile while(num_disp==0){ try{ wait(); }catch(Interrupted. Exception e){e. print. Stack. Trace(); } } num_disp--; return true; } public synchronized void restituisci. Licenza(){ num_disp++; notify(); } } Concorrenza 38
public class Utente extends Thread{ String nome; Manager. Licenze manager; long minuti; public Utente(String nome, Manager. Licenze manager, long minuti){ this. nome = nome; this. manager = manager; this. minuti = minuti; } Concorrenza 39
public void run(){ if(manager. richiedi. Licenza(minuti)){ System. out. println(“L’utente "+nome+" ha preso una licenza"); try{ sleep(minuti*60000); }catch(Interrupted. Exception e){e. print. Stack. Trace(); } manager. restituisci. Licenza(); System. out. println(“L’utente " + nome + " ha lasciato la licenza dopo " + minuti + " minuti"); } else{ System. out. println("Errore: L’utente " + nome + " ha richiesto una licenza per un periodo superiore a 120 minuti. "); } } } Concorrenza 40
public class Esempio{ Utente[] clienti; Manager. Licenze manager; public Esempio(int n){ clienti = new Utente[n]; manager = new Manager. Licenze(); } public static void main(String[] args){ Esempio es = new Esempio(5); es. clienti[0] = new Utente("utente 1", es. manager, 30); es. clienti[1] = new Utente("utente 2", es. manager, 45); es. clienti[2] = new Utente("utente 3", es. manager, 120); es. clienti[3] = new Utente("utente 4", es. manager, 120); es. clienti[4] = new Utente("utente 5", es. manager, 120); es. clienti[0]. start(); es. clienti[1]. start(); es. clienti[2]. start(); es. clienti[3]. start(); es. clienti[4]. start(); } Concorrenza } 41
Output L'utente 1 ha acquisito una licenza. L'utente 2 ha acquisito una licenza. L'utente 3 ha acquisito una licenza. L'utente 4 ha acquisito una licenza. L'utente 1 ha rilasciato la licenza dopo 30 minuti L'utente 5 ha acquisito una licenza. L'utente 2 ha rilasciato la licenza dopo 45 minuti L'utente 3 ha rilasciato la licenza dopo 120 minuti L'utente 4 ha rilasciato la licenza dopo 120 minuti L'utente 5 ha rilasciato la licenza dopo 120 minuti Concorrenza 42
Esercizio: sala da ballo • In una sala da ballo, m cavalieri (threads) e n dame (risorse; senza offesa) sono impegnati nel ballo liscio. Si ha m>n. Lo stato delle risorse è definito dall'array: int [n] Cavaliere. In. Coppia. Con; dove Cavaliere. In. Coppia. Con[j] == i se e solo se la dama j balla in coppia con il cavaliere i e Cavaliere. In. Coppia. Con[j]== 0 se la dama j è libera. Si suppone il valore iniziale 0 per ogni dama; dopo l’inizializzazione ogni dama è sempre in coppia, salvo il transitorio durante le riassegnazioni. • Lo stato dei cavalieri è definito dall'array: int [m] stato; stato[i] assume valori: 0 (indefinito), 1 (In. Coppia), 2 (In. Crisi), 3 (Senza. Dama) Concorrenza 43
• Prima dell’inizializzazione il valore è indefinito per ogni elemento; l’inizializzazione porta ogni cavaliere nello stato In. Coppia (assegnando una dama) oppure nello stato Senza. Dama (che equivale alla richiesta di ballare in coppia con una qualsiasi dama che rimanga libera). • Per ogni coppia, trascorso un certo tempo dalla formazione, il cavaliere i manifesta l’intenzione di formare una coppia diversa: il cavaliere i passa nello stato In. Crisi, che equivale a dichiarare l’intenzione di rilasciare la risorsa. Il cavaliere i individua anche una dama con la quale vorrebbe ballare. La selezione è casuale ed è svolta dal metodo int dama. Che. Affascina(int Indice. Di. Cavaliere). • Le risorse sono rilasciate due per volta: se e solo se il cavaliere h che è in coppia con la dama selezionata dal cavaliere i è a sua volta In. Crisi, le dame in coppia con i e h divengono libere e formano due nuove coppie. Ciascuna di esse può essere assegnata, oltre che a i o ad h, a uno qualunque dei cavalieri che si trovano nello stato Senza. Dama. La selezione è eseguita in modo casuale dal metodo int il. Preferito. Di(int Indice. Di. Dama). A seconda che ottenga o meno l’assegnazione, ciascuno dei cavalieri i e h passa nello stato In. Coppia oppure nello stato Senza. Dama. • I processi che si trovano nello stato In. Coppia sono in esecuzione; la transizione nello stato In. Crisi o Senza. Dama provoca la loro sospensione. • Realizzare il monitor Sala. Da. Ballo permettere ai cavalieri di ballare con le dame.
public class Ballo. Liscio { /** Le condizioni di funzionamento del metodo main richiedono di fornire un numero di cavalieri strettamente superiore del numero delle dame ed un numero di dame strettamente superiore a 2. */ public static void main(String [] args) { int dame = Integer. parse. Int(args[0]); int cavalieri = Integer. parse. Int(args[1]); // aggiungere controlli nel caso le due condizioni d'ingresso // siano errate Sala. Da. Ballo sballo= new Sala. Da. Ballo(dame, cavalieri); System. out. println("Inizino le danze"); for (int i=1; i <= cavalieri; i++) { Cavaliere c = new Cavaliere(i, sballo); c. start(); } } } 45
import java. util. Random; public class Cavaliere extends Thread { private int indice; private Sala. Da. Ballo sballo; // Il cavaliere conosce il suo nome e quello della sala da ballo public Cavaliere(int i, Sala. Da. Ballo sb) { indice = i; sballo = sb; } /** Il cavaliere balla con una dama finchè non si invaghisce di un'altra. * Passerà, dunque, tra stati di ballo e sedute al tavolino. */ public void run() { sballo. inizializzazione(indice); int dama. Assegnata = sballo. la. Mia. Dama(indice); Random gen = new Random(); while (true) { System. out. println("Il cavaliere "+indice+" balla con " + dama. Assegnata); try { sleep(gen. next. Int(2000)); } catch (Interrupted. Exception e) {} System. out. println("Il cavaliere" + indice + " e' in crisi"); sballo. coppia. In. Crisi(indice); dama. Assegnata = sballo. la. Mia. Dama(indice); } } } 46
- Slides: 46