Esame 23/02/2023
Domanda A:
Spiegare che cosa consiste la modalità kernel, per quale scopo esiste, come avviene il passaggio a tale modalità ed il ritorno da tale modalità.
Risposta:
Domanda B:
Quali chiamate di sistema vengono effettuate tipicamente da una shell di Unix per eseguire un comando? Perché?
Unix
Risposta:
Domanda C:
Spiegare che cosa comporta la chiamata pthread_cond_wait(&cond, &m)
per il thread che la effettua, evidenziando il ruolo di entrambi gli argomenti.
Risposta:
Domanda D:
Se nel contesto dello scheduling della CPU a breve termine diciamo che un processo o thread sta soffrendo di starvation (morte di fame), che cosa vuol dire? In quale stato (running, ready, waiting) si trova?
Che cosa si intende per CPU burst? Nello scheduling della CPU a breve termine si vorrebbero preferire processi/thread con CPU burst brevi o lunghi? Perché? Questo comporta il rischio di starvation?
Risposta:
Domanda E:
Spiegare che cosa si intende per page fault (mancanza di pagina), che cosa deve fare in tale caso il sistema operativo, senza descrivere algoritmi per i quali nel corso sono state viste varie soluzioni, ma limitandosi ad indicare i requisiti per gli stessi. Che cosa si può intendere come "meccanismo" e come "politica" in questo caso?
Risposta:
Domanda F:
Per la soluzione presentata nel corso per il problema di sincronizzazione dei cinque filosofi riportata qui sotto, illustrare lo scopo delle singole operazioni della funzione take_forks
indicanco in particolare che cosa sono mutex
e s[i]
, quali operazioni possono essere sospensive, e in quali casi in termini dell'avanzamaneto degli altri processi/thread coinvolti.
void philosopher(int i){
while(TRUE){
think();
take_forks(i);
eat();
put_forks(i);
}
}
void take_forks(int i){
down(&mutex);
state[i] = HUNGRY;
test(i);
up(&mutex);
down(&s[i]);
}
void put_forks(int i){
down(&mutex);
state[i] = THINKING;
test(LEFT);
test(RIGHT);
up(&mutex);
}
void test(int i){
if(state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] != EATING){
state[i] = EATING;
up(&s[i]);
}
}
Risposta:
Esame 19/02/2020
Domanda A:
Spiegare che cosa si intende per multiprogrammazione, perché la si è introdotta e che relazione c’è tra grado di multiprogrammazione ed utilizzazione delle CPU.
Risposta:
La multiprogrammazione è una tecnica nella quale più job vengono caricati in RAM e, quando il processo inizia un I/O Burst (quindi la CPU in questa periodo non verrebbe utilizzata) il Sistema Operativo effettua un context switch ad un altro processo, in modo tale che la CPU venga sfruttata al massimo. Quando il I/O Burst termina il sistema operativo torna ad eseguire il processo iniziale.

Si è introdotta per riuscire ad avere uno pseudo parralleismo tra processi. Il livello di multiprogrammazione (ovvero il numero di processi caricati simultaneamte in RAM) è correllato alla utilizzazione della CPU.
Domanda B:
Spiegare che cosa si intende per trap e quale relazione ha con il sistema operativo. Fare un esempio di trap relativo alla gestione della memoria.
Risposta:
La trap deve essere vista come un interrupt software. Le trap sono un meccanismo di segnalazione con cui il sistema operativo entra in azione eseguendo il codice dell'handler di quella specifica trap. Il codice dell'handler si trova nel kernel del sistema operativo e non può essere modificato, nemmeno dal kernel stesso.
La trap può avvenire per svariati motivi, tra cui:
-
un programma tenta di eseguire una divisione per zero
-
OPCode non valido
-
System calls
-
Page Fault
Le trap posso essere gestite in modo diverso, per esempio il processo viene terminato. Oppure si gestisce la trap e si torna all'esecuzione del proceso (System Calls, o Page Fault).
In particolare il Page Fault accade quando la pagina del processo non è presente in RAM, il Page Fault Handler deve gestire questa cosa (prendedo dal disco e caricando su RAM la pagina corretta). Dopo che il Page Fault Handler ha caricato in RAM la pagina del processo viene ri eseguita l'istuzione che ha causato il page fault.
Domanda C:
Descrivere le operazioni sui semafori ed uno pseudo-codice per la loro realizzazione.
Risposta:
I semafori sono un meccanismo di sincronizzazione fra processi (o threads), in particolare è un meccanismo utilizzato per gestire le corse critiche, ovvero che due processi, nello stesso momento, vedono lo stesso valore in una variabile condivisa.
Godono di queste operazioni:
-
init/create
: creazione del semaforo -
destroy
: cancellazione del semaforo -
up
: incremento il valore del semaforo -
down
: decremento il valore del semaforo
In particolare quando un processo effettua una up
:
-
se il valore del semaforo è > 0 incremento il valore
-
se il valore del semaforo è uguale a 0 non incremento il valore del semaforo ma risveglio il processo che era in attesa di entrare in corsa critica.
Invece per la down
abbiamo che:
-
se il valore del semaforo è > 0 decremento il valore
-
se il valore del semaforo è uguale a 0 lo stato del processo viene impostato a bloccato, e resterà tale fino a quando non verrà risvegliato da una up su quel semaforo.
Per implementare i semafori abbiamo bisogno di un'istruzione ISA che sia atomica (ovvero indivisibile), dato che sia la up
che la down
sono corse critiche. Questa istruzione prende il nome di TestAndSet(&lock)
.
Infatti la realizzione della up e della down è la seguente:
up
:
while(TestAndSet(&s.lock));
if(s.queue != EMPTY){
t = dequeue(s.queue); //Estraggo un thread dalla coda
t.status = READY; //Imposto il thread appena estratto come pronto
}
else{
s.val++;
}
s.lock = 0;
down
:
while(TestAndSet(&s.lock));
if(s.val == 0){
enqueue(s.queue, t); //T è il thread corrente
s.lock = 0;
t.status = BLOCKED; //Imposto lo stato del thread corrente a bloccato
scheduler(); //Lo scheduler scegliera un nuovo thread da eseguire
dispatcher();
}
else{
s.val--;
s.lock = 0;
}
Domanda D:
Spiegare che cosa si intende per deadlock e quale o quali, tra le condizioni necessarie affinché si possa realizzare, sono rese false nella soluzione del problema dei filosofi vista nel corso.
Risposta:
Il deadlock (o stallo) è una condizione in cui un processo rimane in attesa che venga sbloccato da un altro processo che a sua volta è bloccato, come nell'esempio qui sotto:

Le condizioni per la quale un processo può essere vittima di deadlock sono le seguenti (tutte e quattro devono essere vere):
- le risorse sono allocate in mutua esclusione (e se no, perché dovrebbe attendere)
- le risorse non sono preemptive: non ha senso portarle via al processo/thread che le sta usando (es. stampante; mentre per la CPU il costo è accettabile)
- un p/t a cui sono allocate risorse ne può richiedere altre (hold and wait, allocazione parziale)
- si ha attesa circolare nel senso già indicato: ogni p/t attende una risorsa detenuta da un altro dell’insieme
Per il problema dei filosofi abbiamo il caso numero 3, per risolvere questo problema utilizziamo i semafori privati, in modo da riuscire a prendere entrambe le risorse contemporaneamente.
Domanda E:
Spiegare che cosa si intende per CPU burst. Indicare se nello scheduling a breve termine è opportuno favorire la scelta di processi/threads con CPU burst brevi oppure processi/threads con CPU burst lunghi, e perché.
Risposta:
Con CPU burst si intende un periodo del processo nella quale viene utilizzato in modo continuativo la CPU. Nello scheduling a breve termine è opportuno dare priorità ai processi con CPU Burst brevi, perché il peso del CPU Burst in esecuzione viene prolungato nel tempo. Infatti sapendo la seguente formula (per 4 processi) abbiamo che: T_{medio} = (4T_1+3T_2+2T_3+T_4)/4, dove T è la durata di un processo.
Esistono algoritmi appositi per risolvere questo problema: per esempio il Short Job First (SJF) ed il Short Remaning TIme Next (SRTN).
Domanda F:
Quante chiamate di sistema vengono effettuate se si esegue il seguente programma? Motivare la risposta.
int main(){
fork();
fork();
fork();
printf("Duprè\n");
}