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 cosi` il conto. Gli
altri membri della famiglia, cioe` 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 puo` 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 ilSuoConto;
int maxSpesa;
int tempo;
Cons(int m, int t, Conto c) {
ilSuoConto = c;
maxSpesa = m;
tempo = t;
}
public void run () {
while (true) {
if(!ilSuoConto.ritira((int)(Math.random()*maxSpesa)))
System.out.println("Non riesco a tirar fuori i soldi!");
else
System.out.println("Riesco a tirar fuori i soldi!");
try {
sleep(tempo);
} catch(InterruptedException ie) {
System.out.println(“ERRORE!");
}
}
}
}
Concorrenza
3
public class Marito extends Thread {
private Conto ilMioConto;
Marito(Conto c) {
ilMioConto = c;
}
public void run() {
while (true) {
ilMioConto.deposita((int)(Math.random()*1000));
try {
sleep(6000);
} catch(InterruptedException 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
• I selvaggi di una tribù mangiano servendosi da una pentola
comune.
• La pentola può contenere P porzioni di cibo (con P non
necessariamente maggiore del numero di selvaggi). Ogni
selvaggio 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 selvaggi e del cuoco e la gestione
della pentola.
Soluzione
Class Pentola {
final int P = 40;
private int nPorzioni;
public Pentola() {
nPorzioni = P;
}
public syncronized void prendiPorzione(){
while ( ! (nPorzioni > 0) )
try { wait(); }
catch (InterruptedException e ) {
System.out.println(“ERRORE!!!!");
}
nPorzioni--;
System.out.println("Pentola: presa porzione");
notifyAll();
}
public syncronized void riempiPentola(){
while ( ! (nPorzioni == 0) )
try { wait(); }
catch (InterruptedException e ) {
System.out.println(“ERRORE!!!!");
}
nPorzioni = P;
System.out.println("Pentola: riempita di porzioni");
notifyAll();
}
}
Class Cuoco extends Thread{
private Pentola pentola;
public Cuoco(Pentola p) {
pentola=p;
}
public void run (){
while(true){
pentola.riempiPentola();
System.out.println(“cuoco: ho riempito la pentola”);
}
}
}
Class Selvaggio extends Thread{
private Pentola pentola;
public Selvaggio(Pentola p) {
pentola=p;
}
public void run (){
while(true){
pentola.prendiPorzione();
System.out.println(“selvaggio:” +
“ ho preso una porzione”);
}
}
}
Class Test {
public static void main(String[] args) {
Pentola p=new Pentola();
Cuoco c=newCuoco(p)
Selvaggio s1=new Selvaggio(p);
Selvaggio s2=new Selvaggio(p);
Selvaggio s3=new Selvaggio(p);
c.start();
s1.start(); s2.start(); s3.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.
0
1
PI
PO
2
3
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 (InterruptedException e) { }
q = item;
full = true;
notify();
}
public synchronized char get () {
while (!full)
try { wait(); }
catch (InterruptedException 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].charAt(0)(int)'0'].put(commands[i].charAt(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 puo` 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 (InterruptedException ie){
ie.printStackTrace();
}
System.out.println("Controllo che la valvola si sia aperta!");
if (valvola.getStato() == 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(InterruptedException ie){ie.printStackTrace(); }}}
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 getStato() {
long t = 0;
return stato;}
System.out.println("sono la "+name);
}
try{
t = (long)(5500*Math.random());
sleep(t);
} catch (InterruptedException ie) {ie.printStackTrace();}
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 (InterruptedException ie) {ie.printStackTrace();}
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 (InterruptedException 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 (InterruptedException 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 (InterruptedException 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 getSection(){
if (busy) {
return false;
} else {
busy = true;
return true;
}
}
public synchronized void releaseSection() {
busy = false;
}
}
Concorrenza
33
public class Author extends Thread{
int numSections;
Section Sections[10];
getSection(int n)
{
if(numSections<2)
if(Sections[n].getSection(this))
{
numSections++;
}
}
Concorrenza
34
releaseSection(int n) {
Sections[n].releaseSection();
NumSections--;
}
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 ManagerLicenze {
private int num_disp;
public ManagerLicenze(){
num_disp = 4;
}
Concorrenza
37
public synchronized boolean richiediLicenza(long minuti){
if(minuti>120)
return false;
//ci mettiamo in attesa finchè non c'è una licenza disponibile
while(num_disp==0){
try{
wait();
}catch(InterruptedException e){e.printStackTrace();}
}
num_disp--;
return true;
}
public synchronized void restituisciLicenza(){
num_disp++;
notify();
}
}
Concorrenza
38
public class Utente extends Thread{
String nome;
ManagerLicenze manager;
long minuti;
public Utente(String nome, ManagerLicenze
manager, long minuti){
this.nome = nome;
this.manager = manager;
this.minuti = minuti;
}
Concorrenza
39
public void run(){
if(manager.richiediLicenza(minuti)){
System.out.println(“L’utente "+nome+" ha preso una licenza");
try{
sleep(minuti*60000);
}catch(InterruptedException e){e.printStackTrace();}
manager.restituisciLicenza();
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;
ManagerLicenze manager;
public Esempio(int n){
clienti = new Utente[n];
manager = new ManagerLicenze();
}
public static void main(String[] args){
Esempio es = new Esempio(5);
es.clienti[0] = new Utente("utente1", es.manager, 30);
es.clienti[1] = new Utente("utente2", es.manager, 45);
es.clienti[2] = new Utente("utente3", es.manager, 120);
es.clienti[3] = new Utente("utente4", es.manager, 120);
es.clienti[4] = new Utente("utente5", 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 utente1 ha acquisito una licenza.
L'utente utente2 ha acquisito una licenza.
L'utente utente3 ha acquisito una licenza.
L'utente utente4 ha acquisito una licenza.
L'utente utente1 ha rilasciato la licenza dopo 30 minuti
L'utente utente5 ha acquisito una licenza.
L'utente utente2 ha rilasciato la licenza dopo 45 minuti
L'utente utente3 ha rilasciato la licenza dopo 120 minuti
L'utente utente4 ha rilasciato la licenza dopo 120 minuti
L'utente utente5 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] CavaliereInCoppiaCon;
dove CavaliereInCoppiaCon[j] == i se e solo se la dama j balla in
coppia con il cavaliere i e CavaliereInCoppiaCon[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 (InCoppia), 2 (InCrisi), 3
(SenzaDama)
Concorrenza
43
• Prima dell’inizializzazione il valore è indefinito per ogni elemento; l’inizializzazione
porta ogni cavaliere nello stato InCoppia (assegnando una dama) oppure nello stato
SenzaDama (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 InCrisi,
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 damaCheAffascina(int IndiceDiCavaliere).
• 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 InCrisi, 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 SenzaDama. La selezione è eseguita in modo casuale dal metodo int
ilPreferitoDi(int IndiceDiDama). A seconda che ottenga o meno l’assegnazione,
ciascuno dei cavalieri i e h passa nello stato InCoppia oppure nello stato
SenzaDama.
• I processi che si trovano nello stato InCoppia sono in esecuzione; la transizione
nello stato InCrisi o SenzaDama provoca la loro sospensione.
• Realizzare il monitor SalaDaBallo per permettere ai cavalieri di ballare con le
dame.
public class BalloLiscio {
/** 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.parseInt(args[0]);
int cavalieri = Integer.parseInt(args[1]);
// aggiungere controlli nel caso le due condizioni d'ingresso
// siano errate
SalaDaBallo sballo= new SalaDaBallo(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 SalaDaBallo sballo;
// Il cavaliere conosce il suo nome e quello della sala da ballo
public Cavaliere(int i, SalaDaBallo 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 damaAssegnata = sballo.laMiaDama(indice);
Random gen = new Random();
while (true) {
System.out.println("Il cavaliere "+indice+" balla con " + damaAssegnata);
try { sleep(gen.nextInt(2000)); } catch (InterruptedException e) {}
System.out.println("Il cavaliere" + indice + " e' in crisi");
sballo.coppiaInCrisi(indice);
damaAssegnata = sballo.laMiaDama(indice);
}
}
}
46
Scarica

ppt - Esercitazioni ingegneria software