Prove scritte 2021
Prova 2021/09/15
Esercizio C1
Consegna
Esercizio c.1: Scrivere il monitor alrv (at least rendez-vous) che fornisce una sola procedure entry: procedure entry void at_least(int n) Quando un processo chiama la funzione at_least vuol dire che vuole sincronizzarsi con un insieme di almeno n processi (incluso il chiamante). Esempi: Se un processo chiama at_least(1) non si blocca. Se il processo p chiama at_least(2) si blocca, se poi il processo q chiama at_least(2) oppure at_least(1) si sbloccano sia p sia q (la richiesta di p è soddisfatta, ne aspettava almeno 2, p e q) Se il processo p chiama at_least(2) si blocca, se poi il processo q chiama at_least(3) si blocca anch'esso perché sebbene la richiesta di p possa essere soddisfatta, q non può ancora sbloccarsi: ci sono solo 2 processi in attesa mentre q ne vuole 3. Un terzo processo che chiami at_least(x) con x=1,2,3 li sblocca tutti. Hint: sia w[k ] il numero dei processi in attesa di essere in almeno k (quelli che hanno chiamato at_least(k) e non hanno completato l'esecuzione della funzione). Sia s[n]=∑ k=1 n w[k ] (rappresenta il numero di processi soddisfacibili: e.g. se ci sono 4 processi in attesa, potrebbero essere soddisfatte le richieste dei processi che ne aspettano almeno 2, almeno 3 o almeno 4). Preso, se esiste, il massimo indice m tale che s[m]≥m tutti i processi in attesa di essere in n, per n≤m possono essere sbloccati.
1. Soluzione proposta
Soluzione proposta da Flecart
extern int MAX; // il massimo numero di attesa
monitor alrv {
int w[MAX];
int s[MAX];
condition c[MAX];
init() {
for (int i = 0; i < MAX; i++) {
w[i] = s[i] = 0;
}
}
procedure entry void at_least(int n) {
if (n >= MAX || n <= 0) raise error;
int i;
for (i = n; i < MAX; i++) s[i]++;
for (i = MAX - 1; i > 0; i--) {
if (s[i] >= i) break;
}
if (i > 0) {
for (int j = 0; j <= i; j++) {
while (w[j] > 0) {
c[j].signal();
w[j]--;
}
}
s[0] = 0;
for (int i = 1; i < MAX; i++) {
s[i] = w[i] + s[i - 1];
}
} else {
w[n]++;
c[n].wait();
}
}
}
Prova 2021/06/23
Esercizio C1
Consegna
Esercizio c.1: Scrivere il monitor delayvalue con una sola procedure entry:
int delay(int value);
Il monitor deve sospendere i primi NDELAY processi che chiamano la delay. Le successive chiamate di delay devono mantenere costante il numero di processi sospesi, ogni successiva chiamata devo riattivare il primo processo in attesa prima di sospendersi, la delay ritorna il valore passato come parametro dal processo che ne ha riattivato l'esecuzione. e.g. se NDELAY è 2:
P1: delay(44) -> P1 si sospende P2: delay(40) -> P2 si sospende P3: delay(42) -> P1 si riattiva e ritorna 42, P3 si sospende P4: delay(22) -> P2 si riattiva e ritorna 22, P4 si sospende
Soluzione proposta 1
Soluzione proposta da Flecart, da controllare
// variabile definita altrove.
extern int NDELAY;
class Monitor {
Queue<condition> stopped;
int curr_value;
Monitor {
stopped = Queue<condition>();
curr_value = 0;
}
int delay(int value) {
curr_value = value;
if (stopped.size() == NDELAY) {
condition first = stopped.dequeue();
first.signal();
}
condition c = new condition();
stopped.enqueue(c);
c.wait();
return curr_value;
}
}
Esercizio c2
Consegna
Esercizio c.2: Implementare usando semafori ordinari (fair, fifo) un servizio di semafori a priorità lifo che fornisca le seguenti primitive:
void PLP(int prio); void PLV()
PLP e PLV si devono comportare rispettivamente come P e V. Quando la PLV deve riattivare un processo sceglie fra quelli in attesa quello a priorità massima, nel caso siano presenti più processi a priorità massima sceglie quello in attesa da meno tempo.
Soluzione proposta 1
Esercizio c2 (da controllare) da Flecart.
Stack<semaphore> stack[MAX_PRIORITY];
int num_V = 0;
semaphore mutex(1);
void PLP(int prio) {
mutex.P();
if (num_V > 0) {
num_V--;
mutex.V();
return;
}
semaphore sem = semaphore(0);
stack[prio].push(sem);
mutex.V();
sem.P();
mutex.V();
}
void PLV() {
mutex.P();
for (int i = MAX_PRIORITY - 1; i >= 0; i--) {
if (stack[i].size() > 0) {
sem = stack[i].pop();
sem.V();
return;
}
}
num_V++;
mutex.V();
}