Prima Provetta – corso Sistemi Operativi 0809 – 21/11/08
SOLUZIONI
Generalità (5.5 punti totali)
1) Gli algoritmi del Kernel possono eseguire una chiamata di sistema?(0.9punti)
2) Si supponga che un Sistema Operativo si organizzato a livelli secondo il seguente schema:
nucleo|gestione_memoria|gestione_processi|utente. Il tempo medio di un context switch sia
di 0.01 ms. Si supponga che in media i processi richiedono 12 operazioni di memoria e 8
creazioni di processi. Qual'e' il tempo medio di overhead? (1.1punti)
3) Si supponga che un Sistema Operativo concorrente utilizzi la schedulazione in Time Sharing
con ritorno in coda d'attesa illustrata nella seguente figura d'esempio:
P3
P2
P1
...
0
5
10
15 20
25
Si assuma che in un certo istante ci siano tre processi concorrenti di durata diversa. Si
scelgano arbitrariamente le durate dei singoli processi e la durata del quanto temporale Q .
Quali sono i tre tempi di servizio (differenza tra il tempo di fine esecuzione e tempo di
arrivo) dei singoli processi? (2punti)
4) Definire due esempi di risorse logiche e due tipi di risorse fisiche. Caratterizzarle in termini
di condivisibilià e sottraibilità. (1.5punto)
Soluzione
1) sebbene non ci sia nulla che vieta al kernel di chiamare una system call, perchè l'istruzione
Trap che tipicamente realizza l'interruzione SW è utilizzabile anche dal kernel, l' uso di una
chiamata di sistema con il meccanismo delle trap è privo di senso, perchè costituisce un
costo inutile: il kernel potrebbe chiamare una routine del krnel mediaqnte una chiamata di
procedura. Tuttavia non viene fatto perchè le chiamate all'interno del kernel sono poche e
disciplinate. Le chiamate di sistema sono fatte per consentire ai processi utente di utilizzare
algoritmi del nucleo.
2) Nella ipotesi descritta una chiamata di sistema per la gestione della memoria costa 2
attraversamenti per la chiamata e due attraversamenti per il ritorno, cioè 0,04 ms.
Analogamente una chiamata per la gestione dei processi costa 0,02 ms. Quindi il tempo
medio di overhead è 12*0.04+8*0.02 = 0,48+0,16ms = 0,64ms
3) Si tratta di ipotizzare le durate del quanto e dei singoli processi. Se per esempio Q=2, P1=8,
P2=9, P3=7 la schedulazione time sharing con ritorno alla coda d'attesa diventa:
Qui P2 termina perchè ha eseguito 9 unità temporali
P1 P1 P2 P2 P3 P3 P1 P1 P2 P2 P3 P3 P1 P1 P2 P2 P3 P3 P1 P1 P2 P2 P3 P2
0
1
2
3
4
5
6
7
8
9
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Qui P1 termina perchè ha eseguito 8 unità temporali
Qui P3 termina perchè ha eseguito 7 unità temporali
Quindi i tempi di servizio sono: P1=20, P2=24, P3=23
4) due tipi di risorse logiche possono essere: codice rientrate (condivisibile e sottraibile) e una
struttura dati (non condivisibile e non sottraibile). Due tipi di risorse fisiche possono essere
l'unità centrale (condivisibile e sottraibile) e la stampante (non condivisibile e non
sottraibile)
Modelli a code (7 punti totali)
5) Si assuma che in un sistema operativo con una CPU e senza iterazioni di I/O le frequenza
d'arrivo e di terminazioni siano valori interi. Se la frequenza di terminazione dei processi è
di 10 terminazione/secondo, quale deve essere la frequenza di arrivo dei processi tale che il
sistema sia stabile? (1.5punto)
Qual'è la probabilità di utilizzazione CPU in questo caso?(1 punto)
Soluzione
Il sistema è stabile se ρ<1. Visto che come espresso nel problema le frequenze sono numeri interi
l'unica possibilità è che λ=9 arrivi al secondo (se fosse 10 si avrebbe ρ=1).
La probabilità di utilizzazione è uguale a ρ, cioè 0.9 .
6) Un sistema di elaborazione sia strutturato in questo modo:
(1)
CPU
Arrivi Poissoniani
(2)
device
Si tratta di un sistema ciclico con una CPU e un device. La CPU è caratterizzata da una
frequenza media di terminazione µ1=10 e il device da una frequenza di servizio µ2. Il
sistema è collegato a un generatore Poissoniano di processi con frequenza di arrivo λ=10
arrivi/secondo. Il deviatore resta sulla posizione di sinistra (1) per 400ms per alimentare il
sistema di elaborazione e poi viene spostato sulla posizione di destra (2).
Calcolare un valore del tempo di servizio del device µ2 tale che la probabilità di
utilizzazione della CPU sia maggiore del 60%. (4.5 punti)
Soluzione
Un generatore di 10 processi al secondo per 0.4 secondi produce 4 processi, che entrano nel sistema
e aspettano nella coda della cpu. Visto che l'utilizzazione della cpu è pari a ρ(1-ρN)/(1-ρN+1), si
verifica immediatamente che un valore di ρ tale che la probabilità sia maggior di 0.6 può essere
ρ>0.7. Per ρ=0.7, infatti si ha che la probabilità è 0.7(1-0.74)/1-0.75)= 0.7(1-0.24)/(1-0.168)=0.639.
Da cui, visto che ρ=µ2/µ1, si ha µ2=µ1*ρ=7 e conseguentemente il tempo di servizio medio < 1/7.
Naturalmente 0.7 non è un valore preciso perchè per averlo bisognerebbe risolvere una equazione
del 5 ordine; fortunatamente il problema richiede solo un valore del tempo di serviziotale che
l'utilizzazione sia maggiore del 60%,
Strumenti linguistici per la concorrenza(5 punti totali)
Si supponga di voler realizzare in Java due metodi che funzionino in maniera simile alle istruzioni
COBEGIN/COEND del Concurrent Pascal. Precisamente, si vogliono scrivere le seguenti
procedure:
public void Cobegin(Thread t[], int n){
…
}
public void Coend(Thread t[], int n){
…
}
dove t[] è un array di puntatori a Thread inizializzato altrove ed n è il numero di Thread.
Si chiede:
7) scrivere il codice di due metodi in modo tale che Cobegin() esegua in concorrenta tutti I
thread dati in argomento e Coend() aspetti la terminazione di tutti I thread in argomento.
(2.5 punti)
8) cosa si puo' dire sulla potenza di questa soluzione rispetto agli originali
COBEGIN/COEND? (2.5 punti)
Soluzione
7) un codice di Cobegin è tipicamente for(i=0;i<n;i++) t[i].start();
mentre un codice di Coend potrebbe essere for(i=0;i<n;i++) t[i].join();
8) la potenza di questa scrittura è maggiore perchè sono possibili anche incroci di precedenze
Programmazione concorrente (7.5 punti totali)
Sia dato il seguente codice Java (per motivi di semplicità si tratta di codice incompleto, il candidato
non si soffermi sugli aspetti linguistici ma solo su quelli sostanziali) .
Si tratta di una applicazione multithreaded, nella quale i thread condividono le seguenti variabili,
tutte definite esternamente: matrici a[M][M], b[M][M], c[M][M], t[M][M], dove M=2, le variabili
i,j ed il semaforo mutex inizializzato a 0.
// codice Java
class P extends Thread{ //thread Prodotto
public void run()
{
c[i][j]=0; for(k=0; k<M; k++) c[i][j] += a[i][k]*b[k][j]; }
}
class S extends Thread{ //Thread Stampa
public void run(){
mutex.down()
for(l=0; <M; l++) for(m=0; m<M; m++) System.out.println(c[l][m]+” ”);
}
}
class Y extends Thread{ //Thread sincronizzatore
public void run()
{ for(l=0; <M; l++) t[i][l].join(); }
}
class Matrix{ //realizza la funzione matriciale
public static void main(){
Thread t[][]=new Thread[M][M]; //matrice di puntatori a MxM Threads
Thread y[]=new Thread[M]; //matrice di puntatori a M Threads
S s=new S();
Inizializza(a,b,M); //inizializza le matrici a,b e la variabile M
mutex.up();
for(i=0;i<M;i++){
for(j=0;j<M;j++){
t[i][j]=new P(); t[i][j].start();
}
y[i]=new Y(); y[i].start(); y[i].join();
}
s.start(); s.join(),
}
In base a questo codice, si risponda alle seguenti domande:
9) cosa realizza questo programma? (1.5 punti)
10) tracciare il grafo delle precedenze della applicazione (3.4 punti)
11) semplificare il grafo (1.8 punti)
12) modificare il codice per riportare le semplificazioni (0.8)
Soluzione
9) il programma realizza un prodotto matriciale concorrente: ogni elemento della matrice C
viene elaborato in concorrenza con gli altri
10) innanzitutto vediamo che funzionalmente il programma si comporta come segue:
Inizializza
t[0][1]
t[0][0]
sincronizza
t[1][0]
t[1][1]
sincronizza
stampa
cioè il calcolo degli elementi della matrice prodotto avviene per concorrentemente per
righe. Dopo ogni riga c'è una barriera di sincronizzazione che assicura che il calcolo
della riga sia terminato.
Il grafo delle precedenze è il seguente:
inizializza
t[0][0]
t[1][0]
t[0][1]
t[1][1]
s
y[0]
y[1]
L'arco da inizializza a stampa è dovuto alla presenza del semaforo mutex.down in stampa:
stampa aspetta che inizializza metta in up il semaforo e questo succede quando inizializza
finisce.
11) l'arco da inizializza a stampa è implicito e qindi può essere eliminato
12) di conseguenza si possono eliminare le istruazioni mutex.up e mutex.down.
Stallo (5 punti)
13) Sia dato il seguente stato attuale dei 4 processi. Il vettore delle risorse esistenti è
[16, 15, 8, 6]. Dire se il sistema è in stallo.
Risorse Allocate
R1 R2 R3
R4
Risorse richieste
R1 R2 R3
R4
Proc.1
2
3
1
0
4
1
1
1
Proc.2
4
8
0
0
2
2
2
2
Proc.3
2
2
0
0
4
1
2
0
Proc.4
4
2
3
2
0
0
1
3
Soluzione
13) In queste condizioni le risorse esistenti sono V=(4 0 4 4). L'unico processo che può essere
eseguito è P4 che quando termina rilascia le risorse allocate e ci si trova con: V=(8 2 7 6). Poi
esegue P1 e dopo la sua terminazione V diventa ( 10 5 8 6). Poi esegue P2 e dopo la sua
terminazione V=(14 13 8 6). Infine P3 e quando tutti I processi finiscono ci si ritrova con le risorse
esistenti.
Quindi il sistema non è in stallo perchè tutti I processi possono essere eseguiti.