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.