Difference between revisions of "Prove scritte 2021"
m (→Esercizio c2) |
|||
(12 intermediate revisions by 2 users not shown) | |||
Line 62: | Line 62: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | == Es G1 == | ||
+ | === consegna === | ||
+ | |||
+ | Sia dato l'algoritmo di rimpiazzamento modulo che data una memoria di NF frame , se avviene un page | ||
+ | fault in corrispondenza dell'i-mo elemento della stringa di riferimenti modulo sceglie come pagina vittima quella che | ||
+ | occupa il frame i % NF. | ||
+ | Es. se NF fosse 3, la prima pagina viene messa nel frame 1 perché 1 % 3 = 1, se l'undicesimo elemento della stringa | ||
+ | causa un page fault, si elimina la pagina nel frame 2 (11 % 3 = 2). | ||
+ | A) Considerare la stringa di riferimenti seguente e mostrare il funzionamento di modulo nei casi NF = 3 e NF = 4: | ||
+ | 1 2 3 4 5 3 3 3 1 5 | ||
+ | B) modulo è un algoritmo a stack? | ||
+ | |||
+ | === Soluzione proposta (da controllare) === | ||
+ | [[User:Flecart|Flecart]] ([[User talk:Flecart|talk]]) 14:44, 4 May 2023 (CEST) | ||
+ | |||
+ | <pre> | ||
+ | Caso in cui NF=3 | ||
+ | allora | ||
+ | 1 X X 1 | ||
+ | 1 2 X 2 | ||
+ | 1 2 3 3 | ||
+ | 4 2 3 4 | ||
+ | 4 5 3 5 | ||
+ | 4 5 3 3 | ||
+ | 4 5 3 3 | ||
+ | 4 5 3 3 | ||
+ | 1 5 3 1 | ||
+ | 1 5 3 5 | ||
+ | |||
+ | Caso in cui NF=4 | ||
+ | 1 X X X 1 | ||
+ | 1 2 X X 2 | ||
+ | 1 2 3 X 3 | ||
+ | 1 2 3 4 4 | ||
+ | 5 2 3 4 5 | ||
+ | 5 2 3 4 3 | ||
+ | 5 2 3 4 3 | ||
+ | 5 2 3 4 3 | ||
+ | 1 2 3 4 1 | ||
+ | 5 2 3 4 5 | ||
+ | |||
+ | Allora, l'algoritmo non è a stack perché nella penultima accesso al frame ho nel caso NF=3 che | ||
+ | {1, 5, 3}, ma questo non è contenuto in {1, 2, 3, 4}. | ||
+ | </pre> | ||
= Prova 2021/09/15 = | = Prova 2021/09/15 = | ||
Line 135: | Line 181: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | === 2. Soluzione proposta === | ||
Soluzione proposta da [https://so.v2.cs.unibo.it/wiki/index.php/User:Flecart Flecart friend],regalo a flecart la proprietà intellettuale di questa soluzione | Soluzione proposta da [https://so.v2.cs.unibo.it/wiki/index.php/User:Flecart Flecart friend],regalo a flecart la proprietà intellettuale di questa soluzione | ||
Line 169: | Line 217: | ||
} | } | ||
+ | </syntaxhighlight> | ||
+ | === Soluzione proposta 3 (da controllare) === | ||
+ | Proposta da [[User:SpookyWiki|SpookyWiki]] ([[User talk:SpookyWiki|talk]]) 11:41, 25 May 2023 (CEST) | ||
+ | |||
+ | <syntaxhighlight lang="C"> | ||
+ | monitor alrv { | ||
+ | int maxindex; | ||
+ | Map<int, int> waiting4[]; | ||
+ | Map<int, condition> ok2go[] | ||
+ | |||
+ | alrv() { | ||
+ | maxindex = 0; | ||
+ | waiting4 = new Map<int, int>(); | ||
+ | ok2go = new Map<int, condition>(); | ||
+ | } | ||
+ | |||
+ | procedure int check() { //procedura che controlla che i processi in attesa fino n possano essere sbloccati o meno | ||
+ | int sum = 0; | ||
+ | int m = 0; | ||
+ | do { | ||
+ | m++ | ||
+ | sum += waiting4[m]; | ||
+ | } while(m < maxindex && sum >= m) | ||
+ | return sum >= m ? m : m - 1; | ||
+ | } | ||
+ | |||
+ | procedure entry void at_least(int n) { | ||
+ | if(waiting4[n] == null) { | ||
+ | waiting4.add(n); | ||
+ | waiting4[n]++; | ||
+ | ok2.add(n); | ||
+ | } | ||
+ | if (n > maxindex) | ||
+ | maxindex = n; | ||
+ | int m; | ||
+ | if ((m = check(n)) > 0) { | ||
+ | for(int i = 1; i <= m; i++) { | ||
+ | ok2[i].signal(); | ||
+ | waiting4[i] = 0; | ||
+ | } | ||
+ | } else { | ||
+ | ok2go[n].wait(); | ||
+ | ok2go[n].signal(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | == Esercizio C2 == | ||
+ | Dato un servizio di message passing sincrono scrivere, senza fare uso di processi server, un servizio di | ||
+ | message passing sincrono concatenato che abbia le seguenti primitive: | ||
+ | void chained_send (T msg, list_of_pids dests) | ||
+ | T chained_recv(void) | ||
+ | La funzione chained_send deve fare in modo che tutti i processi indicati nella lista dests ricevano il messaggio. Il | ||
+ | processo che chiama la chained_send si blocca solo fino a quando il primo processo della lista dests non chiama una | ||
+ | chained_recv, il primo si sblocca quando il secondo chiama la chained_recv e così via. | ||
+ | ( la funzione chained_recv riceve messaggi provenienti da qualsiasi mittente) | ||
+ | |||
+ | |||
+ | === Soluzione proposta 1 (da controllare) === | ||
+ | * proposta da [[User:Flecart|Flecart]] ([[User talk:Flecart|talk]]) 18:37, 16 January 2023 (CET) | ||
+ | |||
+ | <syntaxhighlight lang="C"> | ||
+ | void chained_send(T msg, list_of_pids dests) { | ||
+ | if (dests.len() < 1) return ERROR; | ||
+ | else if (dests.len() == 1) { | ||
+ | pid head = dests[0]; | ||
+ | ssend(<msg, NULL>, head); | ||
+ | } else { | ||
+ | <head, rest> = dests[0], dests[1:]; | ||
+ | ssend(<msg, rest>, head); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | T chained_recv(void) { | ||
+ | <msg, rest> = srecv(ANY); | ||
+ | if (rest == NULL) return msg; | ||
+ | |||
+ | if (rest.len() == 1) { | ||
+ | pid head = rest[0]; | ||
+ | ssend(<msg, NULL>, head); | ||
+ | } else if (rest.len() > 1) { | ||
+ | <head, rest2> = rest[0], rest[1:]; | ||
+ | ssend(<msg, rest2>, head); | ||
+ | } | ||
+ | |||
+ | return msg; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Soluzione proposta 2 (da controllare) === | ||
+ | Proposta da [[User:SpookyWiki|SpookyWiki]] ([[User talk:SpookyWiki|talk]]) 12:20, 23 May 2023 (CEST) | ||
+ | |||
+ | <syntaxhighlight lang="C"> | ||
+ | void chained_send(T msg, list_of_pids dests) { | ||
+ | if ( dests.length() < 1) | ||
+ | return; | ||
+ | pid_t dest = dests.pop(0); //rimuovo e prendo il primo destinatario | ||
+ | ssend(<msg, dests>, dest); | ||
+ | } | ||
+ | |||
+ | T chained_recv(void) { | ||
+ | <msg, dests> == srecv(ANY); | ||
+ | if(dests.length() > 0) { //il messaggio deve essere ancora inviato ad altri | ||
+ | pid_t dest = dests.pop(0); | ||
+ | ssend(<msg, dests>, dest); | ||
+ | } | ||
+ | return msg; | ||
+ | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 247: | Line 405: | ||
} | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Soluzione proposta 3 (da controllare) === | ||
+ | Proposta da [[User:SpookyWiki|SpookyWiki]] ([[User talk:SpookyWiki|talk]]) 12:05, 25 May 2023 (CEST) | ||
+ | |||
+ | Si assume una politica FIFO delle condition, NDELAY non variabile d'ambiente ma parametro passato all'inizializzazione. | ||
+ | |||
+ | <syntaxhighlight lang="C"> | ||
+ | monitor delayvalue { | ||
+ | int ndelay; | ||
+ | int in; | ||
+ | int lastvalue; | ||
+ | condition ok2return; | ||
+ | |||
+ | delay(int NDELAY) { | ||
+ | ndelay = NDELAY; | ||
+ | in = 0; | ||
+ | lastvalue = 0; | ||
+ | } | ||
+ | |||
+ | procedure entry int delay(int value) { | ||
+ | if (in >= ndelay) { | ||
+ | lastvalue = value; | ||
+ | ok2return.signal(); | ||
+ | } else | ||
+ | in++; | ||
+ | ok2return.wait(); | ||
+ | return lastvalue; | ||
+ | } | ||
+ | |||
+ | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 420: | Line 609: | ||
return p; | return p; | ||
} | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | === Soluzione proposta 3 === | ||
+ | |||
+ | Soluzione proposta da [[User:Barba|zBarba]] ([[User talk:Barba|talk]]) 14:47, 20 January 2024 (CET) | ||
+ | <syntaxhighlight lang="C"> | ||
+ | monitor bss: | ||
+ | list<T> buffer | ||
+ | int nget | ||
+ | condition ok2put | ||
+ | condition ok2get | ||
+ | |||
+ | procedure entry void put(T value){ | ||
+ | buffer.add(value) | ||
+ | if(nget==0){ | ||
+ | ok2put.wait() | ||
+ | ok2put.signal() //cascata di signal | ||
+ | }else if(nget>0){ | ||
+ | ok2get.signal() | ||
+ | buffer.clear() | ||
+ | } | ||
+ | } | ||
+ | |||
+ | procedure entry list<T> get(void){ | ||
+ | ok2put.signal() | ||
+ | if(buffer.isEmpty()){ | ||
+ | nget++ | ||
+ | ok2get.wait() | ||
+ | ok2get.signal() //cascata di signal | ||
+ | nget-- | ||
+ | } | ||
+ | return buffer | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 473: | Line 696: | ||
all_messages[sender].enqueue(<message>); | all_messages[sender].enqueue(<message>); | ||
} while(true); | } while(true); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | === Soluzione proposta 2 === | ||
+ | |||
+ | Soluzione proposta da [[User:Flecart|Flecart]] ([[User talk:Flecart|talk]]) 13:05, 7 March 2023 (CET) | ||
+ | dovrebbe essere più semplice della precedente. | ||
+ | |||
+ | <syntaxhighlight lang="C"> | ||
+ | sasend(message, destination) { | ||
+ | pid t = getpid(); | ||
+ | asend(<message, t>, destination); | ||
+ | } | ||
+ | |||
+ | extern int MAX_PID; | ||
+ | |||
+ | // storerà tutti i messaggi che ricevo che non riesco a utilizzare subito | ||
+ | queue<message> msgs[MAX_PID]; | ||
+ | sarecv(senders) { | ||
+ | if (senders == NULL) { | ||
+ | senders = {0, 1, ..., MAX_PID}; | ||
+ | } | ||
+ | |||
+ | for (pid_t sender : senders) { | ||
+ | if (msgs[sender].size() > 0) { | ||
+ | message_t msg = msgs[sender].dequeue(); | ||
+ | return msg; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | while (True) { | ||
+ | msg, pid = arecv(ANY); | ||
+ | if (pid in senders) { | ||
+ | return msg; | ||
+ | } else { | ||
+ | msgs[pid].enqueue(msg); | ||
+ | } | ||
} | } | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> |
Latest revision as of 14:47, 20 January 2024
Prova 21/07/2021
Es C1 (da correggere)
Soluzione proposta da Flecart friend,regalo a flecart la proprietà intellettuale di questa soluzione
class node{
node parent;
sq sq1;
cond c;
}
class BinTree{
vector<node> base;
void create(int N){
base=new vector<node>(2^N);
for(int i=0;i<2^N;i++)
base[i]=new node(null,0,new cond);
for(int i=1;i<=N;i++){
for(int j=0;j<2^(N-i);j++){
get(j,i-1).parent=get(j+i,i-1).parent=new node(null,0,new cond);
}
}
}
node get(int i,int level){
return get(base[i],level);
}
node get(node n,int level){
if(level==0){
return node;
}
return get(node.parent,level-1);
}
}
class Torneo{
BinTree bin(N);
int forma[2^N];
bool win;
bool gioca(int i,int turno,int forma){
forma[i]=forma;
if null==bin.get(i,turno).sq1{
bin.get(i,turno).sq1=i;
bin.get(i,turno).c.wait();
return !win;
}else{
sq1= bin.get(i,turno).sq1;
if(forma[sq1]==forma[i]){
win=random();
}else{
win=forma[sq1]<forma[i];
}
bin.get(i,turno).signal();
}
return win;
}
}
Es G1
consegna
Sia dato l'algoritmo di rimpiazzamento modulo che data una memoria di NF frame , se avviene un page fault in corrispondenza dell'i-mo elemento della stringa di riferimenti modulo sceglie come pagina vittima quella che occupa il frame i % NF. Es. se NF fosse 3, la prima pagina viene messa nel frame 1 perché 1 % 3 = 1, se l'undicesimo elemento della stringa causa un page fault, si elimina la pagina nel frame 2 (11 % 3 = 2). A) Considerare la stringa di riferimenti seguente e mostrare il funzionamento di modulo nei casi NF = 3 e NF = 4: 1 2 3 4 5 3 3 3 1 5 B) modulo è un algoritmo a stack?
Soluzione proposta (da controllare)
Flecart (talk) 14:44, 4 May 2023 (CEST)
Caso in cui NF=3 allora 1 X X 1 1 2 X 2 1 2 3 3 4 2 3 4 4 5 3 5 4 5 3 3 4 5 3 3 4 5 3 3 1 5 3 1 1 5 3 5 Caso in cui NF=4 1 X X X 1 1 2 X X 2 1 2 3 X 3 1 2 3 4 4 5 2 3 4 5 5 2 3 4 3 5 2 3 4 3 5 2 3 4 3 1 2 3 4 1 5 2 3 4 5 Allora, l'algoritmo non è a stack perché nella penultima accesso al frame ho nel caso NF=3 che {1, 5, 3}, ma questo non è contenuto in {1, 2, 3, 4}.
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();
}
}
}
2. Soluzione proposta
Soluzione proposta da Flecart friend,regalo a flecart la proprietà intellettuale di questa soluzione
class Monitor{
min_heap<(int,cond)> h;
void at_least(int n){
int sum=0;
int max_to_sblock= -INF;
cond c = new cond(n);
h.push((n,c));
// la heap viene visitata in maniera crescente
for(auto f=h.begin_iter();null!=f.next();f++) {
sum++;
if(f.0<=sum){
max_to_sblock =f.0;
}
}
for(auto f=h.begin_iter();null!=f.next();f++) {
if(f.0<=max_to_sblock){
f.1.signal();
h.remove(c);
}
}
if(n>max_to_sblock){
c.wait();
}
free(c)
}
}
Soluzione proposta 3 (da controllare)
Proposta da SpookyWiki (talk) 11:41, 25 May 2023 (CEST)
monitor alrv {
int maxindex;
Map<int, int> waiting4[];
Map<int, condition> ok2go[]
alrv() {
maxindex = 0;
waiting4 = new Map<int, int>();
ok2go = new Map<int, condition>();
}
procedure int check() { //procedura che controlla che i processi in attesa fino n possano essere sbloccati o meno
int sum = 0;
int m = 0;
do {
m++
sum += waiting4[m];
} while(m < maxindex && sum >= m)
return sum >= m ? m : m - 1;
}
procedure entry void at_least(int n) {
if(waiting4[n] == null) {
waiting4.add(n);
waiting4[n]++;
ok2.add(n);
}
if (n > maxindex)
maxindex = n;
int m;
if ((m = check(n)) > 0) {
for(int i = 1; i <= m; i++) {
ok2[i].signal();
waiting4[i] = 0;
}
} else {
ok2go[n].wait();
ok2go[n].signal();
}
}
}
Esercizio C2
Dato un servizio di message passing sincrono scrivere, senza fare uso di processi server, un servizio di message passing sincrono concatenato che abbia le seguenti primitive:
void chained_send (T msg, list_of_pids dests) T chained_recv(void)
La funzione chained_send deve fare in modo che tutti i processi indicati nella lista dests ricevano il messaggio. Il processo che chiama la chained_send si blocca solo fino a quando il primo processo della lista dests non chiama una chained_recv, il primo si sblocca quando il secondo chiama la chained_recv e così via. ( la funzione chained_recv riceve messaggi provenienti da qualsiasi mittente)
Soluzione proposta 1 (da controllare)
void chained_send(T msg, list_of_pids dests) {
if (dests.len() < 1) return ERROR;
else if (dests.len() == 1) {
pid head = dests[0];
ssend(<msg, NULL>, head);
} else {
<head, rest> = dests[0], dests[1:];
ssend(<msg, rest>, head);
}
}
T chained_recv(void) {
<msg, rest> = srecv(ANY);
if (rest == NULL) return msg;
if (rest.len() == 1) {
pid head = rest[0];
ssend(<msg, NULL>, head);
} else if (rest.len() > 1) {
<head, rest2> = rest[0], rest[1:];
ssend(<msg, rest2>, head);
}
return msg;
}
Soluzione proposta 2 (da controllare)
Proposta da SpookyWiki (talk) 12:20, 23 May 2023 (CEST)
void chained_send(T msg, list_of_pids dests) {
if ( dests.length() < 1)
return;
pid_t dest = dests.pop(0); //rimuovo e prendo il primo destinatario
ssend(<msg, dests>, dest);
}
T chained_recv(void) {
<msg, dests> == srecv(ANY);
if(dests.length() > 0) { //il messaggio deve essere ancora inviato ad altri
pid_t dest = dests.pop(0);
ssend(<msg, dests>, dest);
}
return msg;
}
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
// 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();
free(c);
return curr_value;
}
}
Soluzione proposta 2
Soluzione proposta da Flecart friend, regalo la proprietà intellettuale a flecart.
- Controllato da Flecart (talk) 18:10, 16 January 2023 (CET), corretto se si assume la FIFO interna della condition.
monitor dalayvalue{
#define NDELAY 22
int blocked=0;
int lastvalue=0;
cond c;
int dalay(int value){
lastvalue=value;
if(blocked<NDELAY){
blocked++;
c.wait();
}else if(blocked==NDELAY){
c.signal();
c.wait();
}
return lastvalue;
}
}
Soluzione proposta 3 (da controllare)
Proposta da SpookyWiki (talk) 12:05, 25 May 2023 (CEST)
Si assume una politica FIFO delle condition, NDELAY non variabile d'ambiente ma parametro passato all'inizializzazione.
monitor delayvalue {
int ndelay;
int in;
int lastvalue;
condition ok2return;
delay(int NDELAY) {
ndelay = NDELAY;
in = 0;
lastvalue = 0;
}
procedure entry int delay(int value) {
if (in >= ndelay) {
lastvalue = value;
ok2return.signal();
} else
in++;
ok2return.wait();
return lastvalue;
}
}
Esercizio c2
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 Flecart.
controllato:
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();
}
Prova 2021/05/26
Consegna c1
Esercizio c.1: Un buffer sincrono strampalato (bss) ha due procedure entry: void put(T value) list of T get(void) La entry put viene utilizzata per aggiungere un elemento e la entry get per leggere tutti quelli disponibili. Se più processi chiamano la put quando nessun processo è in attesa per una get, rimangono tutti bloccati. Quando successivamente un processo chiama la get riceve la lista di tutti gli elementi inseriti con le put e tutti i processi vengono sbloccati. Se il buffer è vuoto tutti i processi che chiamano la get rimangono bloccati. quando un processo chiama successivamente la put tutti i processi in attesa per la get si sbloccano e ricevono lo stesso valore di ritorno: una lista contenente il solo valore passato come parametro alla put.
Soluzione proposta 1
Soluzione proposta da Flecart
int num = 0; // se è positiva rappresenta numero di gets che aspettano, se negativa, numero di puts
semaphore semput(0);
semaphore semget(0);
semaphore mutex(1);
list<T> global_list;
void put(T value) {
//< await(num > 0) --> global_list.add(value) >
mutex.P();
if (num <= 0) {
num--;
mutex.V();
semput.P();
num++;
}
global_list.add(value);
if (num < 0)
semput.V();
else
semget.V();
return;
}
list of T get() {
list<T> local_list;
mutex.P();
if (num >= 0) {
num++;
mutex.V();
semget.P();
num--;
} else {
semput.V();
semget.P();
}
local_list = global_list; // fa deep copy
if (num > 0) {
semget.V();
} else {
global_list = list<T>();
mutex.V();
}
return local_list;
}
Soluzione proposta 2
Soluzione proposta da Gio
class bss{
int waiting_put=0;
int waiting_get=0;
cond cw,cg;
queue<T> q;
void put(T value){
q.push(T);
if(waiting_get>0){
cg.signal()
}else{
waiting_put++;
cw.wait();
waiting_put--;
}
}
list<T> get(){
if(waiting_put>0){
while(waiting_put>0){
cw.signal();
}
}else{
waiting_get++;
cg.wait();
waiting_get--;
}
list<T> p= q.tolist();
if(waiting_get>0){
cg.signal();
}
q.removeAll();
return p;
}
}
Soluzione proposta 3
Soluzione proposta da zBarba (talk) 14:47, 20 January 2024 (CET)
monitor bss:
list<T> buffer
int nget
condition ok2put
condition ok2get
procedure entry void put(T value){
buffer.add(value)
if(nget==0){
ok2put.wait()
ok2put.signal() //cascata di signal
}else if(nget>0){
ok2get.signal()
buffer.clear()
}
}
procedure entry list<T> get(void){
ok2put.signal()
if(buffer.isEmpty()){
nget++
ok2get.wait()
ok2get.signal() //cascata di signal
nget--
}
return buffer
}
esercizio c2
Dato un servizio di message passing asincrono implementare un servizio di message passing asincrono a selezione di mittenti (samp) senza fare uso di processi server. Il servizio samp ha due primitive: sasend(message , destination) sarecv(senders) dove senders è un insieme. la sarecv restituisce il primo messaggio che uno dei processi in senders ha spedito al processo ricevente usando la sasend (o spedito da qualsiasi processo se senders è vuoto).
Soluzione proposta 1
Soluzione proposta da Flecart (talk) 15:29, 15 January 2023 (CET)
sasend(message, destination) {
pid t = getpid();
asend(<message, t>, destination);
}
// variabile privata di sarecv
queue all_messages[MAX_PROC];
// stora tutti i messaggi ricevuti, lo utilizziamo come queue per tutti, con
// anche la possibilità di rimuovere in un punto a scelta.
vector<<messages, pid>> msg;
sarecv(senders) {
if (senders.len() == 0) {
if (msg.len() == 0) {
<message, sender> = arecv(ANY);
return message;
} else {
<message, sender> = msg.pop_back();
return message;
}
} else {
do {
for (idx in senders) {
if (all_messages[idx].size() > 0) {
message = all_messages[idx].dequeue();
// rimuove il singolo messaggio dal vector, non tutti quelli uguali.
msg.remove(<message, idx>);
return message;
}
}
<message, sender> = arecv(ANY);
msg.push_back(<message, sender>);
all_messages[sender].enqueue(<message>);
} while(true);
}
}
Soluzione proposta 2
Soluzione proposta da Flecart (talk) 13:05, 7 March 2023 (CET) dovrebbe essere più semplice della precedente.
sasend(message, destination) {
pid t = getpid();
asend(<message, t>, destination);
}
extern int MAX_PID;
// storerà tutti i messaggi che ricevo che non riesco a utilizzare subito
queue<message> msgs[MAX_PID];
sarecv(senders) {
if (senders == NULL) {
senders = {0, 1, ..., MAX_PID};
}
for (pid_t sender : senders) {
if (msgs[sender].size() > 0) {
message_t msg = msgs[sender].dequeue();
return msg;
}
}
while (True) {
msg, pid = arecv(ANY);
if (pid in senders) {
return msg;
} else {
msgs[pid].enqueue(msg);
}
}
}