Difference between revisions of "Prova teorica 2017.05.29"
Jump to navigation
Jump to search
(10 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
− | [ | + | [http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf link al compito] |
− | + | ==Esercizio c.1== | |
+ | ===Soluzione di Mida=== | ||
+ | <syntaxhighlight lang="C"> | ||
− | + | Monitor rb() | |
+ | { | ||
− | + | condition oktorun, oktochiama | |
− | + | int c, punteggio[2], nstudentiP, arrivati | |
+ | int i = [1,2,3,4] | ||
− | < | + | procedure entry nuovaPartita () |
− | + | { | |
+ | punteggio[A] = punteggio [B] = c = arrivati = 0; | ||
+ | |||
+ | } | ||
+ | |||
+ | procedure entry chiama( n ) | ||
+ | |||
+ | { | ||
+ | int k = random(i); | ||
+ | c = k; | ||
+ | if ( nstudentiP < 2 * MAX ) | ||
+ | oktochiama(n).wait(); | ||
+ | for(j=0 ; j<k ; k++) | ||
+ | n inrange(0, MAX-1); | ||
+ | oktorun(n).signal(); | ||
+ | return Punteggio | ||
− | + | } | |
− | + | procedure entry pronto (sq, n) | |
− | |||
− | |||
− | |||
− | + | { | |
− | + | if(max(punteggio) == 10; | |
+ | return 1 | ||
− | + | nstudentiP ++; | |
− | + | if ( nstudentiP >= 2*MAX ) | |
− | + | oktochiama(n).signal(); | |
− | + | oktorun(n).wait(); | |
− | + | arrivati(sq)++; | |
+ | else return 0 | ||
+ | |||
+ | } | ||
− | + | procedure entry allabandiera ( sq, n) | |
− | + | { | |
+ | if ( arrivati(sq) == C ) | ||
+ | punteggio[sq]++; | ||
+ | else punteggio[1-sq]++; | ||
− | + | } | |
− | |||
− | |||
} | } | ||
− | |||
− | |||
− | + | ||
− | + | ||
+ | qualcuno cortesemente può dirmi se può andar bene? | ||
+ | </syntaxhighlight> | ||
− | + | ===Soluzione di Stefano Zaniboni=== | |
− | + | <syntaxhighlight lang="C"> | |
− | + | Monitor rb () { | |
− | + | condition ok2chiama, ok2run[MAX], ok2fine | |
+ | int npronti, punteggio[2], arrivati, c | ||
− | + | procedure entry void nuovapartita() { | |
− | + | c = npronti = arrived punteggio[0] = punteggio[1] = 0 | |
− | + | } | |
− | + | procedure entry int chiama(int *chiamati) { | |
− | + | c = chiamati.length | |
+ | if(npronti < 2 * MAX) | ||
+ | ok2chiama.wait() | ||
+ | for(int i = 0; i < c; i++){ | ||
+ | ok2run[i].signal() | ||
+ | ok2run[i].signal() | ||
+ | } | ||
+ | ok2fine.wait() | ||
+ | if(max(punteggio) == 10) | ||
+ | for(int i = 0; i in range(MAX); i++){ | ||
+ | ok2run[i].signal() | ||
+ | ok2run[i].signal() | ||
+ | } | ||
+ | return punteggio; | ||
+ | } | ||
− | + | procedure entry int pronto(int squadra, int numero) { | |
+ | if(max(punteggio) == 10) | ||
+ | return -1 | ||
+ | npronti++ | ||
+ | if (npronti > 2 * MAX) | ||
+ | ok2chiama.signal() | ||
+ | if(n not in chiamata) | ||
+ | ok2run[n].wait() | ||
+ | npronti-- | ||
+ | if(max(punteggio) == 10) | ||
+ | return -1 | ||
+ | else return 0 | ||
+ | } | ||
− | procedure entry | + | procedure entry void allabandiera(int squadra, int numero) { |
+ | arrived++ | ||
+ | if(arrived = 2 * c) | ||
+ | punteggio[1 - squadra]++ | ||
+ | ok2fine.signal() | ||
+ | } | ||
+ | } | ||
− | |||
− | |||
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
==Esercizio c.2== | ==Esercizio c.2== | ||
+ | |||
+ | ===Soluzione di Stefano Zaniboni=== | ||
+ | <syntaxhighlight lang="C"> | ||
+ | /* | ||
+ | sia dato un servizio di message passing asincrono distratto. Questo servizio si comporta come un servizio di message passing asincrono ma talvolta dimentica la destinazione. | ||
+ | E’ però possibile indicare un processo come “ufficio messaggi smarriti” al quale verranno recapitati tutti i messaggi per i quali il servizio distratto ha dimenticato la destinazione. | ||
+ | |||
+ | Void dmsgsend(pid_t dest, msg_t msg); //si comporta come amsgsend ma può dimenticare la desticazione | ||
+ | msg_t dmsgrecv() //si comporta come amsgrecv(*) | ||
+ | void dset_lost_n_found(pid_t pid); //indica il processo per i messaggi smarriti. | ||
+ | |||
+ | Usando il servizio “distratto” e un processo “ufficio messaggi smarriti”, | ||
+ | implementare un servizio di message passing standard (senza la selezione del mittente in ricezione, la amsgrecv riceve da qualsiasi mittente). | ||
+ | */ | ||
+ | |||
+ | void asend(pid_t dest, msg_t msg){ | ||
+ | dmsgsend(dest,{getpid(), dest, msg}) | ||
+ | } | ||
+ | |||
+ | msg_t arecv(pid_t sender){ | ||
+ | {snd, dst, m} = dmsgrecv() | ||
+ | return m | ||
+ | } | ||
+ | |||
+ | process l+f{ | ||
+ | dset_lost_n_found(getpid()) | ||
+ | while(true){ | ||
+ | {snd, dst, m} = dmsgrecv() | ||
+ | if dst != getpid(){ | ||
+ | asend(dst, {snd, dst, m}) | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
==Esercizio g.1== | ==Esercizio g.1== | ||
− | + | ===Soluzione di GiovanniF=== | |
min = lifo 1234123124123124... | min = lifo 1234123124123124... | ||
lifo = lru 123124123124123124... | lifo = lru 123124123124123124... | ||
+ | |||
+ | --[[User:FedericoB|FedericoB]] ([[User talk:FedericoB|talk]]) 10:17, 16 June 2017 (CEST) <br> | ||
+ | Ho verificato la soluzione:<br> | ||
+ | Il ragionamento da fare qui è: <br> | ||
+ | MIN = LIFO <br> | ||
+ | MIN sceglie la pagina che più tardi nel futuro verrà richiesta <br> | ||
+ | LIFO sceglie l'ultima pagina caricata <br> | ||
+ | Quindi ad ogni page fault l'ultima pagina caricata deve essere quella che più tardi nel futuro verrà richiesta | ||
+ | |||
+ | <pre> | ||
+ | MIN | ||
+ | 1 2 3 4 1 2 3 1 2 4 1 2 3 1 2 4 | ||
+ | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | ||
+ | 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 | ||
+ | 3 4 4 4 3 3 3 4 4 4 3 3 3 4 | ||
+ | # # # # # | ||
+ | |||
+ | LIFO | ||
+ | 1 2 3 4 1 2 3 1 2 4 1 2 3 1 2 4 | ||
+ | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | ||
+ | 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 | ||
+ | 3 4 4 4 3 3 3 4 4 4 3 3 3 4 | ||
+ | # # # # # | ||
+ | </pre> | ||
+ | |||
+ | LIFO = LRU <br> | ||
+ | LRU sceglie la pagina che più precedentemente nel passato è stata richiesta <br> | ||
+ | Quindi ad ogni page fault l'ultima pagina caricata deve essere quella che più precedentemente nel passato è stata richiesta | ||
+ | |||
+ | <pre> | ||
+ | LRU | ||
+ | 1 2 3 1 2 4 1 2 3 1 2 4 1 2 3 | ||
+ | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | ||
+ | 2 2 2 2 2 2 2 2 2 2 2 2 2 2 | ||
+ | 3 3 3 4 4 4 3 3 3 4 4 4 4 | ||
+ | # # # # | ||
+ | |||
+ | LIFO | ||
+ | 1 2 3 1 2 4 1 2 3 1 2 4 1 2 3 | ||
+ | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | ||
+ | 2 2 2 2 2 2 2 2 2 2 2 2 2 2 | ||
+ | 3 3 3 4 4 4 3 3 3 4 4 4 4 | ||
+ | # # # # | ||
+ | </pre> | ||
==Esercizio g.2== | ==Esercizio g.2== | ||
− | #'''Un i-node di un file system tipo ext2 per un errore viene riportato un numero di link maggiore del reale. Cosa può succedere se si continua ad usare il file system? (perchè?) E se il numero di link errato fosse il contrario inferiore al reale cosa potrebbe succedere? (perchè?) | + | #'''Un i-node di un file system tipo ext2 per un errore viene riportato un numero di link maggiore del reale. Cosa può succedere se si continua ad usare il file system? (perchè?) E se il numero di link errato fosse il contrario inferiore al reale cosa potrebbe succedere? (perchè?) ''' <br> Che quando i reali link al i-node verrano eliminati e il numero decrementato questo non raggiungerà mai zero e lo spazio non verrà rilasciato. Se invece il numero di link è inferiore al reale può succedere che con solo l'eliminazione di pochi link al inode l'area del file venga segnata come libera perchè il sistema operativo pensa che l'inode non sia più utilizzato. |
#'''Perchè è necessario usare spinlock in sistemi multiprocessore per implementare kernel di tipo simmetrico (SMP)?''' <br>Perchè la semplice disabilitazione degli interrupt non sarebbe sufficiente in caso di parallelismo reale a prevenire l'accesso a memoria condivisa in concorrenza. Bisogna perciò utilizzare strumenti come gli spinlock che grazie a istruzioni atomiche, per esempio la test-and-set, bloccano l'esecuzione di un processo fino al verificarsi di una condizione. Per evitare il busy wait si possono usare gli spinlock solo per rendere atomiche le istruzioni P e V di un semaforo in modo che la maggior parte del tempo di attesa per entrare in una sezione critica un processo lo passi in stato di wait invece che consumare inutilmente cicli di CPU. | #'''Perchè è necessario usare spinlock in sistemi multiprocessore per implementare kernel di tipo simmetrico (SMP)?''' <br>Perchè la semplice disabilitazione degli interrupt non sarebbe sufficiente in caso di parallelismo reale a prevenire l'accesso a memoria condivisa in concorrenza. Bisogna perciò utilizzare strumenti come gli spinlock che grazie a istruzioni atomiche, per esempio la test-and-set, bloccano l'esecuzione di un processo fino al verificarsi di una condizione. Per evitare il busy wait si possono usare gli spinlock solo per rendere atomiche le istruzioni P e V di un semaforo in modo che la maggior parte del tempo di attesa per entrare in una sezione critica un processo lo passi in stato di wait invece che consumare inutilmente cicli di CPU. | ||
− | #'''Perchè nei sistemi reali l'algoritmo di rimpiazzamento second chance (orologio) viene preferito a LRU sebbene il primo non sia a stack e il secondo sì? | + | #'''Perchè nei sistemi reali l'algoritmo di rimpiazzamento second chance (orologio) viene preferito a LRU sebbene il primo non sia a stack e il secondo sì?''' <br> perchè la gestione dei timestamp richiesti da LRU è costosa nella MMU. |
− | #'''Perchè revocare un'autorizzazione espressa come capability è più difficile che revocare lo stesso diritto quando espresso come access control list?''' | + | #'''Perchè revocare un'autorizzazione espressa come capability è più difficile che revocare lo stesso diritto quando espresso come access control list?''' <br> Perchè le capability sono salvate al interno dello spazio di memoria di ciascun processo mentre le access control list sono legate al file. |
Latest revision as of 10:19, 13 July 2017
Esercizio c.1
Soluzione di Mida
Monitor rb()
{
condition oktorun, oktochiama
int c, punteggio[2], nstudentiP, arrivati
int i = [1,2,3,4]
procedure entry nuovaPartita ()
{
punteggio[A] = punteggio [B] = c = arrivati = 0;
}
procedure entry chiama( n )
{
int k = random(i);
c = k;
if ( nstudentiP < 2 * MAX )
oktochiama(n).wait();
for(j=0 ; j<k ; k++)
n inrange(0, MAX-1);
oktorun(n).signal();
return Punteggio
}
procedure entry pronto (sq, n)
{
if(max(punteggio) == 10;
return 1
nstudentiP ++;
if ( nstudentiP >= 2*MAX )
oktochiama(n).signal();
oktorun(n).wait();
arrivati(sq)++;
else return 0
}
procedure entry allabandiera ( sq, n)
{
if ( arrivati(sq) == C )
punteggio[sq]++;
else punteggio[1-sq]++;
}
}
qualcuno cortesemente può dirmi se può andar bene?
Soluzione di Stefano Zaniboni
Monitor rb () {
condition ok2chiama, ok2run[MAX], ok2fine
int npronti, punteggio[2], arrivati, c
procedure entry void nuovapartita() {
c = npronti = arrived punteggio[0] = punteggio[1] = 0
}
procedure entry int chiama(int *chiamati) {
c = chiamati.length
if(npronti < 2 * MAX)
ok2chiama.wait()
for(int i = 0; i < c; i++){
ok2run[i].signal()
ok2run[i].signal()
}
ok2fine.wait()
if(max(punteggio) == 10)
for(int i = 0; i in range(MAX); i++){
ok2run[i].signal()
ok2run[i].signal()
}
return punteggio;
}
procedure entry int pronto(int squadra, int numero) {
if(max(punteggio) == 10)
return -1
npronti++
if (npronti > 2 * MAX)
ok2chiama.signal()
if(n not in chiamata)
ok2run[n].wait()
npronti--
if(max(punteggio) == 10)
return -1
else return 0
}
procedure entry void allabandiera(int squadra, int numero) {
arrived++
if(arrived = 2 * c)
punteggio[1 - squadra]++
ok2fine.signal()
}
}
Esercizio c.2
Soluzione di Stefano Zaniboni
/*
sia dato un servizio di message passing asincrono distratto. Questo servizio si comporta come un servizio di message passing asincrono ma talvolta dimentica la destinazione.
E’ però possibile indicare un processo come “ufficio messaggi smarriti” al quale verranno recapitati tutti i messaggi per i quali il servizio distratto ha dimenticato la destinazione.
Void dmsgsend(pid_t dest, msg_t msg); //si comporta come amsgsend ma può dimenticare la desticazione
msg_t dmsgrecv() //si comporta come amsgrecv(*)
void dset_lost_n_found(pid_t pid); //indica il processo per i messaggi smarriti.
Usando il servizio “distratto” e un processo “ufficio messaggi smarriti”,
implementare un servizio di message passing standard (senza la selezione del mittente in ricezione, la amsgrecv riceve da qualsiasi mittente).
*/
void asend(pid_t dest, msg_t msg){
dmsgsend(dest,{getpid(), dest, msg})
}
msg_t arecv(pid_t sender){
{snd, dst, m} = dmsgrecv()
return m
}
process l+f{
dset_lost_n_found(getpid())
while(true){
{snd, dst, m} = dmsgrecv()
if dst != getpid(){
asend(dst, {snd, dst, m})
}
}
}
Esercizio g.1
Soluzione di GiovanniF
min = lifo 1234123124123124...
lifo = lru 123124123124123124...
--FedericoB (talk) 10:17, 16 June 2017 (CEST)
Ho verificato la soluzione:
Il ragionamento da fare qui è:
MIN = LIFO
MIN sceglie la pagina che più tardi nel futuro verrà richiesta
LIFO sceglie l'ultima pagina caricata
Quindi ad ogni page fault l'ultima pagina caricata deve essere quella che più tardi nel futuro verrà richiesta
MIN 1 2 3 4 1 2 3 1 2 4 1 2 3 1 2 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 4 4 4 3 3 3 4 4 4 3 3 3 4 # # # # # LIFO 1 2 3 4 1 2 3 1 2 4 1 2 3 1 2 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 3 4 4 4 3 3 3 4 4 4 3 3 3 4 # # # # #
LIFO = LRU
LRU sceglie la pagina che più precedentemente nel passato è stata richiesta
Quindi ad ogni page fault l'ultima pagina caricata deve essere quella che più precedentemente nel passato è stata richiesta
LRU 1 2 3 1 2 4 1 2 3 1 2 4 1 2 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 4 4 4 3 3 3 4 4 4 4 # # # # LIFO 1 2 3 1 2 4 1 2 3 1 2 4 1 2 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 4 4 4 3 3 3 4 4 4 4 # # # #
Esercizio g.2
- Un i-node di un file system tipo ext2 per un errore viene riportato un numero di link maggiore del reale. Cosa può succedere se si continua ad usare il file system? (perchè?) E se il numero di link errato fosse il contrario inferiore al reale cosa potrebbe succedere? (perchè?)
Che quando i reali link al i-node verrano eliminati e il numero decrementato questo non raggiungerà mai zero e lo spazio non verrà rilasciato. Se invece il numero di link è inferiore al reale può succedere che con solo l'eliminazione di pochi link al inode l'area del file venga segnata come libera perchè il sistema operativo pensa che l'inode non sia più utilizzato. - Perchè è necessario usare spinlock in sistemi multiprocessore per implementare kernel di tipo simmetrico (SMP)?
Perchè la semplice disabilitazione degli interrupt non sarebbe sufficiente in caso di parallelismo reale a prevenire l'accesso a memoria condivisa in concorrenza. Bisogna perciò utilizzare strumenti come gli spinlock che grazie a istruzioni atomiche, per esempio la test-and-set, bloccano l'esecuzione di un processo fino al verificarsi di una condizione. Per evitare il busy wait si possono usare gli spinlock solo per rendere atomiche le istruzioni P e V di un semaforo in modo che la maggior parte del tempo di attesa per entrare in una sezione critica un processo lo passi in stato di wait invece che consumare inutilmente cicli di CPU. - Perchè nei sistemi reali l'algoritmo di rimpiazzamento second chance (orologio) viene preferito a LRU sebbene il primo non sia a stack e il secondo sì?
perchè la gestione dei timestamp richiesti da LRU è costosa nella MMU. - Perchè revocare un'autorizzazione espressa come capability è più difficile che revocare lo stesso diritto quando espresso come access control list?
Perchè le capability sono salvate al interno dello spazio di memoria di ciascun processo mentre le access control list sono legate al file.