<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://so.v2.cs.unibo.it/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mattiabiondi</id>
	<title>Sistemi Operativi - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://so.v2.cs.unibo.it/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Mattiabiondi"/>
	<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php/Special:Contributions/Mattiabiondi"/>
	<updated>2026-05-03T11:29:21Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.35.5</generator>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2399</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2399"/>
		<updated>2019-06-12T13:16:37Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// server[] = array contenente il PID di tutti i server&lt;br /&gt;
&lt;br /&gt;
#define BROADCAST server[0]&lt;br /&gt;
&lt;br /&gt;
server[0]&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto da me stesso allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(*, &amp;lt;msg, getpid()&amp;gt;); // se il messaggio l'ho ricevuto da un client o da un altro server lo inoltro a tutti i server (compreso me stesso)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
server[x] // x = 1...N-1&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto dal server[0] allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(BROADCAST, &amp;lt;msg, getpid()&amp;gt;) // se il messaggio l'ho ricevuto da un client lo inoltro al server[0]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 19/06/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.06.19.tot.pdf 2017.06.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare)===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define NATLETI n&lt;br /&gt;
&lt;br /&gt;
condition ok2lancia[NATLETI];&lt;br /&gt;
condition ok2giudice;&lt;br /&gt;
&lt;br /&gt;
int counter[NATLETI];&lt;br /&gt;
int ultimo_tiro;&lt;br /&gt;
float registro[NATLETI][3];&lt;br /&gt;
&lt;br /&gt;
Procedure entry: boolean pronto(int i)&lt;br /&gt;
{&lt;br /&gt;
    if(!(i == 0 &amp;amp;&amp;amp; counter[i] == 0)) // se è il primo lancio non devo metterlo in wait&lt;br /&gt;
        ok2lancia[i].wait()&lt;br /&gt;
    if(counter[i] &amp;lt; 3)&lt;br /&gt;
        return true;&lt;br /&gt;
    else&lt;br /&gt;
        return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void lanciato (int i)&lt;br /&gt;
{&lt;br /&gt;
    counter[i]++;&lt;br /&gt;
    ultimo_tiro = i;&lt;br /&gt;
    ok2giudice.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int lanciofatto()&lt;br /&gt;
{&lt;br /&gt;
    ok2giudice.wait()&lt;br /&gt;
    if(ultimo_tiro == NATLETI-1 &amp;amp;&amp;amp; counter[0] == 3)&lt;br /&gt;
        return -1;  // devo invalidare la condizione per uscire dal while, quindi se nessuno deve più lanciare ritorno -1&lt;br /&gt;
    else&lt;br /&gt;
        return ultimo_tiro;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void registraechiama(int i, float m)&lt;br /&gt;
{&lt;br /&gt;
    registro[i][counter[i]-1] = m; // il secondo indice indica l'iesimo lancio -1 (perchè iniziamo a contare da zero)&lt;br /&gt;
    if(i == NATLETI-1) // se ha appena tirato l'ultimo atleta non posso dare il via a NATLETI (perchè non esiste), quindi faccio ricominciare il giro&lt;br /&gt;
        ok2lancia[0].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2lancia[i+1].signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int classifica()&lt;br /&gt;
{&lt;br /&gt;
    int best[NATLETI];&lt;br /&gt;
    for(int i = 0; i &amp;lt; NATLETI; i++)&lt;br /&gt;
    {&lt;br /&gt;
        for(int j = 0; j &amp;lt; 3; j++)&lt;br /&gt;
        {&lt;br /&gt;
            if(registro[i][j] &amp;gt; best[i])&lt;br /&gt;
                best[i] = registro[i][j];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    best.sort_in_descending_order(); // supponiamo nel nostro pseudolinguaggio esista una funzione di ordinamento qualunque&lt;br /&gt;
    return best;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.02.14.tot.pdf 2015.02.14.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
condition ok2red;&lt;br /&gt;
condition ok2blue;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(color_t color, generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if(buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
    if((&amp;lt;color&amp;gt; == buffer.last()) == color)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2red.wait();&lt;br /&gt;
        else&lt;br /&gt;
            ok2blue.wait();&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(&amp;lt;color, val&amp;gt;);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
    if(buffer.lenght() &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2blue.signal();&lt;br /&gt;
        else&lt;br /&gt;
            ok2red.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if(buffer.lenght == 0)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
    &amp;lt;val&amp;gt; = buffer.dequeue();&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 4:       3 4 5 5 5 5 3 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FIFO:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 4 4 4 4 2 2 2 2 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 5 5 5 5 3 3 3 3 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 0 0 0 0 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 3 3 3 1 1 1 1 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 0 1 2 3 0 1 4 2 0 3 4 1 2 3 4&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 4 5 5 5 3 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LRU:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 4 4 4 2 2 2 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 5 5 5 3 3 3 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 3 3 1 1 1 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
Il problema si può risolvere utilizzando l'algoritmo LRU e la seguente stringa di riferimenti:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 4 3 2 1 5 3 2 4 1 5 4 3 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 03/06/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.06.03.tot.pdf 2014.06.03.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor sabelev&lt;br /&gt;
{&lt;br /&gt;
    #define N n //numero dei piani&lt;br /&gt;
&lt;br /&gt;
    condition ok2enter[N][2]; //piano di partenza e direzione&lt;br /&gt;
    condition ok2exit[N]; //piano di arrivo&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void atfloor(int floor, int direction)&lt;br /&gt;
    {&lt;br /&gt;
        ok2exit[floor].signal(); //da il via al primo del piano che deve uscire&lt;br /&gt;
        ok2enter[floor][direction].signal(); //da il via al primo del piano che deve entrare e deve andare in questa direzione&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void enter(int from, int to)&lt;br /&gt;
    {&lt;br /&gt;
        int direction;&lt;br /&gt;
        if(to &amp;gt; from) //controllo sulla direzione&lt;br /&gt;
            direction = 0;&lt;br /&gt;
        else&lt;br /&gt;
            direction = 1;&lt;br /&gt;
&lt;br /&gt;
        ok2enter[from][direction].wait(); //mi fermo in attesa che arrivi l'ascensore&lt;br /&gt;
        ok2enter[from][direction].signal(); //quando arriva l'ascensore do il via a quello in attesa dopo di me&lt;br /&gt;
        ok2exit[to].wait(); //mi fermo dentro all'ascensore in attesa di uscire&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void exit(int from, int to)&lt;br /&gt;
    {&lt;br /&gt;
        ok2exit[to].signal(); //do il via ad un altro che deve uscire a questo piano come me&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/02/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.02.21.tot.pdf 2014.02.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bbwl&lt;br /&gt;
{&lt;br /&gt;
    #define MAXELEM n&lt;br /&gt;
&lt;br /&gt;
    condition ok2read;&lt;br /&gt;
    condition ok2write;&lt;br /&gt;
    condition ok2log;&lt;br /&gt;
&lt;br /&gt;
    queue q1;&lt;br /&gt;
    queue q2;&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void write(eltype elem)&lt;br /&gt;
    {&lt;br /&gt;
        if (q1.size() &amp;gt;= MAXELEM)&lt;br /&gt;
            ok2write.wait();&lt;br /&gt;
        q1.enqueue(elem);&lt;br /&gt;
        ok2log.signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: eltype read()&lt;br /&gt;
    {&lt;br /&gt;
        if (q2.size == 0)&lt;br /&gt;
            ok2read.wait();&lt;br /&gt;
        eltype elem = q2.dequeue();&lt;br /&gt;
        ok2write.signal();&lt;br /&gt;
        return elem;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: eltype log()&lt;br /&gt;
    {&lt;br /&gt;
        if (q1.size() == 0)&lt;br /&gt;
            ok2log.wait();&lt;br /&gt;
        eltype elem = q1.dequeue();&lt;br /&gt;
        q2.enqueue(elem);&lt;br /&gt;
        ok2read.signal()&lt;br /&gt;
        return elem;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/05/2011 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2011-05-11.con.pdf 2011-05-11.con.pdf]&lt;br /&gt;
=== Esercizio 2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1);&lt;br /&gt;
&lt;br /&gt;
lifocs_enter()&lt;br /&gt;
{&lt;br /&gt;
    s.push(getpid());&lt;br /&gt;
    mutex.p();&lt;br /&gt;
    while(s.lastElement() != getpid())&lt;br /&gt;
    {&lt;br /&gt;
        mutex.v();&lt;br /&gt;
        mutex.p();&lt;br /&gt;
    }&lt;br /&gt;
    s.pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
lifocs_exit()&lt;br /&gt;
{&lt;br /&gt;
    mutex.v();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2398</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2398"/>
		<updated>2019-06-11T13:54:14Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 03/06/2014 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// server[] = array contenente il PID di tutti i server&lt;br /&gt;
&lt;br /&gt;
#define BROADCAST server[0]&lt;br /&gt;
&lt;br /&gt;
server[0]&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto da me stesso allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(*, &amp;lt;msg, getpid()&amp;gt;); // se il messaggio l'ho ricevuto da un client o da un altro server lo inoltro a tutti i server (compreso me stesso)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
server[x] // x = 1...N-1&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto dal server[0] allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(BROADCAST, &amp;lt;msg, getpid()&amp;gt;) // se il messaggio l'ho ricevuto da un client lo inoltro al server[0]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 19/06/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.06.19.tot.pdf 2017.06.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare)===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define NATLETI n&lt;br /&gt;
&lt;br /&gt;
condition ok2lancia[NATLETI];&lt;br /&gt;
condition ok2giudice;&lt;br /&gt;
&lt;br /&gt;
int counter[NATLETI];&lt;br /&gt;
int ultimo_tiro;&lt;br /&gt;
float registro[NATLETI][3];&lt;br /&gt;
&lt;br /&gt;
Procedure entry: boolean pronto(int i)&lt;br /&gt;
{&lt;br /&gt;
    if(!(i == 0 &amp;amp;&amp;amp; counter[i] == 0)) // se è il primo lancio non devo metterlo in wait&lt;br /&gt;
        ok2lancia[i].wait()&lt;br /&gt;
    if(counter[i] &amp;lt; 3)&lt;br /&gt;
        return true;&lt;br /&gt;
    else&lt;br /&gt;
        return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void lanciato (int i)&lt;br /&gt;
{&lt;br /&gt;
    counter[i]++;&lt;br /&gt;
    ultimo_tiro = i;&lt;br /&gt;
    ok2giudice.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int lanciofatto()&lt;br /&gt;
{&lt;br /&gt;
    ok2giudice.wait()&lt;br /&gt;
    if(ultimo_tiro == NATLETI-1 &amp;amp;&amp;amp; counter[0] == 3)&lt;br /&gt;
        return -1;  // devo invalidare la condizione per uscire dal while, quindi se nessuno deve più lanciare ritorno -1&lt;br /&gt;
    else&lt;br /&gt;
        return ultimo_tiro;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void registraechiama(int i, float m)&lt;br /&gt;
{&lt;br /&gt;
    registro[i][counter[i]-1] = m; // il secondo indice indica l'iesimo lancio -1 (perchè iniziamo a contare da zero)&lt;br /&gt;
    if(i == NATLETI-1) // se ha appena tirato l'ultimo atleta non posso dare il via a NATLETI (perchè non esiste), quindi faccio ricominciare il giro&lt;br /&gt;
        ok2lancia[0].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2lancia[i+1].signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int classifica()&lt;br /&gt;
{&lt;br /&gt;
    int best[NATLETI];&lt;br /&gt;
    for(int i = 0; i &amp;lt; NATLETI; i++)&lt;br /&gt;
    {&lt;br /&gt;
        for(int j = 0; j &amp;lt; 3; j++)&lt;br /&gt;
        {&lt;br /&gt;
            if(registro[i][j] &amp;gt; best[i])&lt;br /&gt;
                best[i] = registro[i][j];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    best.sort_in_descending_order(); // supponiamo nel nostro pseudolinguaggio esista una funzione di ordinamento qualunque&lt;br /&gt;
    return best;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.02.14.tot.pdf 2015.02.14.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
condition ok2red;&lt;br /&gt;
condition ok2blue;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(color_t color, generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if(buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
    if((&amp;lt;color&amp;gt; == buffer.last()) == color)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2red.wait();&lt;br /&gt;
        else&lt;br /&gt;
            ok2blue.wait();&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(&amp;lt;color, val&amp;gt;);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
    if(buffer.lenght() &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2blue.signal();&lt;br /&gt;
        else&lt;br /&gt;
            ok2red.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if(buffer.lenght == 0)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
    &amp;lt;val&amp;gt; = buffer.dequeue();&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 4:       3 4 5 5 5 5 3 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FIFO:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 4 4 4 4 2 2 2 2 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 5 5 5 5 3 3 3 3 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 0 0 0 0 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 3 3 3 1 1 1 1 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 0 1 2 3 0 1 4 2 0 3 4 1 2 3 4&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 4 5 5 5 3 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LRU:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 4 4 4 2 2 2 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 5 5 5 3 3 3 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 3 3 1 1 1 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
Il problema si può risolvere utilizzando l'algoritmo LRU e la seguente stringa di riferimenti:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 4 3 2 1 5 3 2 4 1 5 4 3 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 03/06/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.06.03.tot.pdf 2014.06.03.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor sabelev&lt;br /&gt;
{&lt;br /&gt;
    #define N n //numero dei piani&lt;br /&gt;
&lt;br /&gt;
    condition ok2enter[N][1]; //piano di partenza e direzione&lt;br /&gt;
    condition ok2exit[N]; //piano di arrivo&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void atfloor(int floor, int direction)&lt;br /&gt;
    {&lt;br /&gt;
        ok2exit[floor].signal(); //da il via al primo del piano che deve uscire&lt;br /&gt;
        ok2enter[floor][direction].signal(); //da il via al primo del piano che deve entrare e deve andare in questa direzione&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void enter(int from, int to)&lt;br /&gt;
    {&lt;br /&gt;
        int direction;&lt;br /&gt;
        if(to &amp;gt; from) //controllo sulla direzione&lt;br /&gt;
            direction = 0;&lt;br /&gt;
        else&lt;br /&gt;
            direction = 1;&lt;br /&gt;
&lt;br /&gt;
        ok2enter[from][direction].wait(); //mi fermo in attesa che arrivi l'ascensore&lt;br /&gt;
        ok2enter[from][direction].signal(); //quando arriva l'ascensore do il via a quello in attesa dopo di me&lt;br /&gt;
        ok2exit[to].wait(); //mi fermo dentro all'ascensore in attesa di uscire&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void exit(int from, int to)&lt;br /&gt;
    {&lt;br /&gt;
        ok2exit[to].signal(); //do il via ad un altro che deve uscire a questo piano come me&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/02/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.02.21.tot.pdf 2014.02.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bbwl&lt;br /&gt;
{&lt;br /&gt;
    #define MAXELEM n&lt;br /&gt;
&lt;br /&gt;
    condition ok2read;&lt;br /&gt;
    condition ok2write;&lt;br /&gt;
    condition ok2log;&lt;br /&gt;
&lt;br /&gt;
    queue q1;&lt;br /&gt;
    queue q2;&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void write(eltype elem)&lt;br /&gt;
    {&lt;br /&gt;
        if (q1.size() &amp;gt;= MAXELEM)&lt;br /&gt;
            ok2write.wait();&lt;br /&gt;
        q1.enqueue(elem);&lt;br /&gt;
        ok2log.signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: eltype read()&lt;br /&gt;
    {&lt;br /&gt;
        if (q2.size == 0)&lt;br /&gt;
            ok2read.wait();&lt;br /&gt;
        eltype elem = q2.dequeue();&lt;br /&gt;
        ok2write.signal();&lt;br /&gt;
        return elem;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: eltype log()&lt;br /&gt;
    {&lt;br /&gt;
        if (q1.size() == 0)&lt;br /&gt;
            ok2log.wait();&lt;br /&gt;
        eltype elem = q1.dequeue();&lt;br /&gt;
        q2.enqueue(elem);&lt;br /&gt;
        ok2read.signal()&lt;br /&gt;
        return elem;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/05/2011 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2011-05-11.con.pdf 2011-05-11.con.pdf]&lt;br /&gt;
=== Esercizio 2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1);&lt;br /&gt;
&lt;br /&gt;
lifocs_enter()&lt;br /&gt;
{&lt;br /&gt;
    s.push(getpid());&lt;br /&gt;
    mutex.p();&lt;br /&gt;
    while(s.lastElement() != getpid())&lt;br /&gt;
    {&lt;br /&gt;
        mutex.v();&lt;br /&gt;
        mutex.p();&lt;br /&gt;
    }&lt;br /&gt;
    s.pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
lifocs_exit()&lt;br /&gt;
{&lt;br /&gt;
    mutex.v();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2397</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2397"/>
		<updated>2019-06-11T13:45:38Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 03/06/2014 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// server[] = array contenente il PID di tutti i server&lt;br /&gt;
&lt;br /&gt;
#define BROADCAST server[0]&lt;br /&gt;
&lt;br /&gt;
server[0]&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto da me stesso allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(*, &amp;lt;msg, getpid()&amp;gt;); // se il messaggio l'ho ricevuto da un client o da un altro server lo inoltro a tutti i server (compreso me stesso)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
server[x] // x = 1...N-1&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto dal server[0] allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(BROADCAST, &amp;lt;msg, getpid()&amp;gt;) // se il messaggio l'ho ricevuto da un client lo inoltro al server[0]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 19/06/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.06.19.tot.pdf 2017.06.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare)===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define NATLETI n&lt;br /&gt;
&lt;br /&gt;
condition ok2lancia[NATLETI];&lt;br /&gt;
condition ok2giudice;&lt;br /&gt;
&lt;br /&gt;
int counter[NATLETI];&lt;br /&gt;
int ultimo_tiro;&lt;br /&gt;
float registro[NATLETI][3];&lt;br /&gt;
&lt;br /&gt;
Procedure entry: boolean pronto(int i)&lt;br /&gt;
{&lt;br /&gt;
    if(!(i == 0 &amp;amp;&amp;amp; counter[i] == 0)) // se è il primo lancio non devo metterlo in wait&lt;br /&gt;
        ok2lancia[i].wait()&lt;br /&gt;
    if(counter[i] &amp;lt; 3)&lt;br /&gt;
        return true;&lt;br /&gt;
    else&lt;br /&gt;
        return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void lanciato (int i)&lt;br /&gt;
{&lt;br /&gt;
    counter[i]++;&lt;br /&gt;
    ultimo_tiro = i;&lt;br /&gt;
    ok2giudice.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int lanciofatto()&lt;br /&gt;
{&lt;br /&gt;
    ok2giudice.wait()&lt;br /&gt;
    if(ultimo_tiro == NATLETI-1 &amp;amp;&amp;amp; counter[0] == 3)&lt;br /&gt;
        return -1;  // devo invalidare la condizione per uscire dal while, quindi se nessuno deve più lanciare ritorno -1&lt;br /&gt;
    else&lt;br /&gt;
        return ultimo_tiro;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void registraechiama(int i, float m)&lt;br /&gt;
{&lt;br /&gt;
    registro[i][counter[i]-1] = m; // il secondo indice indica l'iesimo lancio -1 (perchè iniziamo a contare da zero)&lt;br /&gt;
    if(i == NATLETI-1) // se ha appena tirato l'ultimo atleta non posso dare il via a NATLETI (perchè non esiste), quindi faccio ricominciare il giro&lt;br /&gt;
        ok2lancia[0].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2lancia[i+1].signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int classifica()&lt;br /&gt;
{&lt;br /&gt;
    int best[NATLETI];&lt;br /&gt;
    for(int i = 0; i &amp;lt; NATLETI; i++)&lt;br /&gt;
    {&lt;br /&gt;
        for(int j = 0; j &amp;lt; 3; j++)&lt;br /&gt;
        {&lt;br /&gt;
            if(registro[i][j] &amp;gt; best[i])&lt;br /&gt;
                best[i] = registro[i][j];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    best.sort_in_descending_order(); // supponiamo nel nostro pseudolinguaggio esista una funzione di ordinamento qualunque&lt;br /&gt;
    return best;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.02.14.tot.pdf 2015.02.14.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
condition ok2red;&lt;br /&gt;
condition ok2blue;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(color_t color, generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if(buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
    if((&amp;lt;color&amp;gt; == buffer.last()) == color)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2red.wait();&lt;br /&gt;
        else&lt;br /&gt;
            ok2blue.wait();&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(&amp;lt;color, val&amp;gt;);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
    if(buffer.lenght() &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2blue.signal();&lt;br /&gt;
        else&lt;br /&gt;
            ok2red.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if(buffer.lenght == 0)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
    &amp;lt;val&amp;gt; = buffer.dequeue();&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 4:       3 4 5 5 5 5 3 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FIFO:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 4 4 4 4 2 2 2 2 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 5 5 5 5 3 3 3 3 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 0 0 0 0 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 3 3 3 1 1 1 1 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 0 1 2 3 0 1 4 2 0 3 4 1 2 3 4&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 4 5 5 5 3 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LRU:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 4 4 4 2 2 2 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 5 5 5 3 3 3 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 3 3 1 1 1 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
Il problema si può risolvere utilizzando l'algoritmo LRU e la seguente stringa di riferimenti:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 4 3 2 1 5 3 2 4 1 5 4 3 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 03/06/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.06.03.tot.pdf 2014.06.03.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor sabelev&lt;br /&gt;
{&lt;br /&gt;
    #define N n //numero dei piani&lt;br /&gt;
&lt;br /&gt;
    condition ok2enter[N][1]; //piano di partenza e direzione&lt;br /&gt;
    condition ok2exit[N]; //piano di arrivo&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void atfloor(int floor, int direction)&lt;br /&gt;
    {&lt;br /&gt;
        ok2exit[floor].signal(); //da il via al primo del piano che deve uscire&lt;br /&gt;
        ok2enter[floor][direction].signal(); //da il via al primo del piano che deve entrare e deve andare in questa direzione&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void enter(int from, int to)&lt;br /&gt;
    {&lt;br /&gt;
        int direction;&lt;br /&gt;
        if(to &amp;gt; from) //controllo sulla direzione&lt;br /&gt;
            direction = 0;&lt;br /&gt;
        else&lt;br /&gt;
            direction = 1;&lt;br /&gt;
&lt;br /&gt;
        ok2enter[from][direction].wait(); //mi fermo in attesa che arrivi l'ascensore&lt;br /&gt;
        ok2enter[from][direction].signal(); //quando arriva l'ascensore do il via a quello in attesa dopo di me&lt;br /&gt;
        ok2exit[to].wait(); //mi fermo dentro all'ascensore in attesa di uscire&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void exit(int from, int to)&lt;br /&gt;
    {&lt;br /&gt;
        ok2exit[to].signal(); //do il via ad un altro che deve uscire a questo piano come me&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/05/2011 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2011-05-11.con.pdf 2011-05-11.con.pdf]&lt;br /&gt;
=== Esercizio 2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1);&lt;br /&gt;
&lt;br /&gt;
lifocs_enter()&lt;br /&gt;
{&lt;br /&gt;
    s.push(getpid());&lt;br /&gt;
    mutex.p();&lt;br /&gt;
    while(s.lastElement() != getpid())&lt;br /&gt;
    {&lt;br /&gt;
        mutex.v();&lt;br /&gt;
        mutex.p();&lt;br /&gt;
    }&lt;br /&gt;
    s.pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
lifocs_exit()&lt;br /&gt;
{&lt;br /&gt;
    mutex.v();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2396</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2396"/>
		<updated>2019-06-11T12:15:45Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// server[] = array contenente il PID di tutti i server&lt;br /&gt;
&lt;br /&gt;
#define BROADCAST server[0]&lt;br /&gt;
&lt;br /&gt;
server[0]&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto da me stesso allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(*, &amp;lt;msg, getpid()&amp;gt;); // se il messaggio l'ho ricevuto da un client o da un altro server lo inoltro a tutti i server (compreso me stesso)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
server[x] // x = 1...N-1&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto dal server[0] allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(BROADCAST, &amp;lt;msg, getpid()&amp;gt;) // se il messaggio l'ho ricevuto da un client lo inoltro al server[0]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 19/06/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.06.19.tot.pdf 2017.06.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare)===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define NATLETI n&lt;br /&gt;
&lt;br /&gt;
condition ok2lancia[NATLETI];&lt;br /&gt;
condition ok2giudice;&lt;br /&gt;
&lt;br /&gt;
int counter[NATLETI];&lt;br /&gt;
int ultimo_tiro;&lt;br /&gt;
float registro[NATLETI][3];&lt;br /&gt;
&lt;br /&gt;
Procedure entry: boolean pronto(int i)&lt;br /&gt;
{&lt;br /&gt;
    if(!(i == 0 &amp;amp;&amp;amp; counter[i] == 0)) // se è il primo lancio non devo metterlo in wait&lt;br /&gt;
        ok2lancia[i].wait()&lt;br /&gt;
    if(counter[i] &amp;lt; 3)&lt;br /&gt;
        return true;&lt;br /&gt;
    else&lt;br /&gt;
        return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void lanciato (int i)&lt;br /&gt;
{&lt;br /&gt;
    counter[i]++;&lt;br /&gt;
    ultimo_tiro = i;&lt;br /&gt;
    ok2giudice.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int lanciofatto()&lt;br /&gt;
{&lt;br /&gt;
    ok2giudice.wait()&lt;br /&gt;
    if(ultimo_tiro == NATLETI-1 &amp;amp;&amp;amp; counter[0] == 3)&lt;br /&gt;
        return -1;  // devo invalidare la condizione per uscire dal while, quindi se nessuno deve più lanciare ritorno -1&lt;br /&gt;
    else&lt;br /&gt;
        return ultimo_tiro;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void registraechiama(int i, float m)&lt;br /&gt;
{&lt;br /&gt;
    registro[i][counter[i]-1] = m; // il secondo indice indica l'iesimo lancio -1 (perchè iniziamo a contare da zero)&lt;br /&gt;
    if(i == NATLETI-1) // se ha appena tirato l'ultimo atleta non posso dare il via a NATLETI (perchè non esiste), quindi faccio ricominciare il giro&lt;br /&gt;
        ok2lancia[0].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2lancia[i+1].signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int classifica()&lt;br /&gt;
{&lt;br /&gt;
    int best[NATLETI];&lt;br /&gt;
    for(int i = 0; i &amp;lt; NATLETI; i++)&lt;br /&gt;
    {&lt;br /&gt;
        for(int j = 0; j &amp;lt; 3; j++)&lt;br /&gt;
        {&lt;br /&gt;
            if(registro[i][j] &amp;gt; best[i])&lt;br /&gt;
                best[i] = registro[i][j];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    best.sort_in_descending_order(); // supponiamo nel nostro pseudolinguaggio esista una funzione di ordinamento qualunque&lt;br /&gt;
    return best;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.02.14.tot.pdf 2015.02.14.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
condition ok2red;&lt;br /&gt;
condition ok2blue;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(color_t color, generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if(buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
    if((&amp;lt;color&amp;gt; == buffer.last()) == color)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2red.wait();&lt;br /&gt;
        else&lt;br /&gt;
            ok2blue.wait();&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(&amp;lt;color, val&amp;gt;);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
    if(buffer.lenght() &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2blue.signal();&lt;br /&gt;
        else&lt;br /&gt;
            ok2red.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if(buffer.lenght == 0)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
    &amp;lt;val&amp;gt; = buffer.dequeue();&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 4:       3 4 5 5 5 5 3 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FIFO:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 4 4 4 4 2 2 2 2 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 5 5 5 5 3 3 3 3 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 0 0 0 0 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 3 3 3 1 1 1 1 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 0 1 2 3 0 1 4 2 0 3 4 1 2 3 4&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 4 5 5 5 3 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LRU:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 4 4 4 2 2 2 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 5 5 5 3 3 3 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 3 3 1 1 1 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
Il problema si può risolvere utilizzando l'algoritmo LRU e la seguente stringa di riferimenti:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 4 3 2 1 5 3 2 4 1 5 4 3 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 03/06/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.06.03.tot.pdf 2014.06.03.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor sabelev&lt;br /&gt;
{&lt;br /&gt;
    #define N n //numero dei piani&lt;br /&gt;
&lt;br /&gt;
    condition ok2enter[N][1]; //piano di partenza e direzione&lt;br /&gt;
    condition ok2exit[N]; //piano di arrivo&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void atfloor(int floor, int direction)&lt;br /&gt;
    {&lt;br /&gt;
        ok2exit[floor].signal(); //da il via al primo del piano che deve uscire&lt;br /&gt;
        ok2enter[floor][direction].signal(); //da il via al primo del piano che deve entrare e deve andare in questa direzione&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void enter(int from, int to)&lt;br /&gt;
    {&lt;br /&gt;
        int direction;&lt;br /&gt;
        if(to &amp;gt; from) //controllo sulla direzione&lt;br /&gt;
            direction = 0;&lt;br /&gt;
        else&lt;br /&gt;
            direction = 1;&lt;br /&gt;
&lt;br /&gt;
        ok2enter[from][direction].wait(); //mi fermo in attesa che arrivi l'ascensore&lt;br /&gt;
        ok2enter[from][direction].signal(); //quando arriva l'ascensore do il via a quello in attesa dopo di me&lt;br /&gt;
        ok2exit[to].wait(); //mi fermo dentro all'ascensore in attesa di uscire&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void exit(int from, int to)&lt;br /&gt;
    {&lt;br /&gt;
        ok2exit[to].signal(); //do il via ad un altro che deve uscire a questo piano come me&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2395</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2395"/>
		<updated>2019-06-10T18:26:11Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 16/07/2014 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// server[] = array contenente il PID di tutti i server&lt;br /&gt;
&lt;br /&gt;
#define BROADCAST server[0]&lt;br /&gt;
&lt;br /&gt;
server[0]&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto da me stesso allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(*, &amp;lt;msg, getpid()&amp;gt;); // se il messaggio l'ho ricevuto da un client o da un altro server lo inoltro a tutti i server (compreso me stesso)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
server[x] // x = 1...N-1&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto dal server[0] allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(BROADCAST, &amp;lt;msg, getpid()&amp;gt;) // se il messaggio l'ho ricevuto da un client lo inoltro al server[0]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 19/06/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.06.19.tot.pdf 2017.06.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare)===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define NATLETI n&lt;br /&gt;
&lt;br /&gt;
condition ok2lancia[NATLETI];&lt;br /&gt;
condition ok2giudice;&lt;br /&gt;
&lt;br /&gt;
int counter[NATLETI];&lt;br /&gt;
int ultimo_tiro;&lt;br /&gt;
float registro[NATLETI][3];&lt;br /&gt;
&lt;br /&gt;
Procedure entry: boolean pronto(int i)&lt;br /&gt;
{&lt;br /&gt;
    if(!(i == 0 &amp;amp;&amp;amp; counter[i] == 0)) // se è il primo lancio non devo metterlo in wait&lt;br /&gt;
        ok2lancia[i].wait()&lt;br /&gt;
    if(counter[i] &amp;lt; 3)&lt;br /&gt;
        return true;&lt;br /&gt;
    else&lt;br /&gt;
        return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void lanciato (int i)&lt;br /&gt;
{&lt;br /&gt;
    counter[i]++;&lt;br /&gt;
    ultimo_tiro = i;&lt;br /&gt;
    ok2giudice.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int lanciofatto()&lt;br /&gt;
{&lt;br /&gt;
    ok2giudice.wait()&lt;br /&gt;
    if(ultimo_tiro == NATLETI-1 &amp;amp;&amp;amp; counter[0] == 3)&lt;br /&gt;
        return -1;  // devo invalidare la condizione per uscire dal while, quindi se nessuno deve più lanciare ritorno -1&lt;br /&gt;
    else&lt;br /&gt;
        return ultimo_tiro;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void registraechiama(int i, float m)&lt;br /&gt;
{&lt;br /&gt;
    registro[i][counter[i]-1] = m; // il secondo indice indica l'iesimo lancio -1 (perchè iniziamo a contare da zero)&lt;br /&gt;
    if(i == NATLETI-1) // se ha appena tirato l'ultimo atleta non posso dare il via a NATLETI (perchè non esiste), quindi faccio ricominciare il giro&lt;br /&gt;
        ok2lancia[0].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2lancia[i+1].signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int classifica()&lt;br /&gt;
{&lt;br /&gt;
    int best[NATLETI];&lt;br /&gt;
    for(int i = 0; i &amp;lt; NATLETI; i++)&lt;br /&gt;
    {&lt;br /&gt;
        for(int j = 0; j &amp;lt; 3; j++)&lt;br /&gt;
        {&lt;br /&gt;
            if(registro[i][j] &amp;gt; best[i])&lt;br /&gt;
                best[i] = registro[i][j];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    best.sort_in_descending_order(); // supponiamo nel nostro pseudolinguaggio esista una funzione di ordinamento qualunque&lt;br /&gt;
    return best;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.02.14.tot.pdf 2015.02.14.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
condition ok2red;&lt;br /&gt;
condition ok2blue;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(color_t color, generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if(buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
    if((&amp;lt;color&amp;gt; == buffer.last()) == color)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2red.wait();&lt;br /&gt;
        else&lt;br /&gt;
            ok2blue.wait();&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(&amp;lt;color, val&amp;gt;);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
    if(buffer.lenght() &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2blue.signal();&lt;br /&gt;
        else&lt;br /&gt;
            ok2red.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if(buffer.lenght == 0)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
    &amp;lt;val&amp;gt; = buffer.dequeue();&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 4:       3 4 5 5 5 5 3 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FIFO:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 4 4 4 4 2 2 2 2 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 5 5 5 5 3 3 3 3 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 0 0 0 0 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 3 3 3 1 1 1 1 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 0 1 2 3 0 1 4 2 0 3 4 1 2 3 4&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 4 5 5 5 3 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LRU:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 4 4 4 2 2 2 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 5 5 5 3 3 3 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 3 3 1 1 1 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
Il problema si può risolvere utilizzando l'algoritmo LRU e la seguente stringa di riferimenti:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 4 3 2 1 5 3 2 4 1 5 4 3 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 03/06/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.06.03.tot.pdf 2014.06.03.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor sabelev&lt;br /&gt;
{&lt;br /&gt;
    #define N n //numero dei piani&lt;br /&gt;
&lt;br /&gt;
    condition ok2enter[N][1]; //piano di partenza e direzione&lt;br /&gt;
    condition ok2exit[N]; //piano di arrivo&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void atfloor(int floor, int direction)&lt;br /&gt;
    {&lt;br /&gt;
        ok2exit[floor].signal(); //da il via al primo del piano che deve uscire&lt;br /&gt;
        ok2enter[floor][direction].signal(); //da il via al primo del piano che deve entrare e deve andare in questa direzione&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void enter(int from, int to)&lt;br /&gt;
    {&lt;br /&gt;
        int direction;&lt;br /&gt;
        if(to &amp;gt; from) //controllo sulla direzione&lt;br /&gt;
            direction = 0;&lt;br /&gt;
        else&lt;br /&gt;
            direction = 1;&lt;br /&gt;
&lt;br /&gt;
        ok2enter[from][direction].wait(); //mi fermo in attesa che arrivi l'ascensore&lt;br /&gt;
        ok2enter[from][direction].signal(); //quando arriva l'ascensore do il via a quello in attesa dopo di me&lt;br /&gt;
        ok2exit[to].wait(); //mi fermo dentro all'ascensore in attesa di uscire&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    procedure entry: void exit(int from, int to)&lt;br /&gt;
    {&lt;br /&gt;
        ok2exit[to].signal(); //do il via ad un altro che deve uscire a questo piano come me&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2392</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2392"/>
		<updated>2019-05-24T17:41:43Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 29/05/2017 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// server[] = array contenente il PID di tutti i server&lt;br /&gt;
&lt;br /&gt;
#define BROADCAST server[0]&lt;br /&gt;
&lt;br /&gt;
server[0]&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto da me stesso allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(*, &amp;lt;msg, getpid()&amp;gt;); // se il messaggio l'ho ricevuto da un client o da un altro server lo inoltro a tutti i server (compreso me stesso)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
server[x] // x = 1...N-1&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto dal server[0] allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(BROADCAST, &amp;lt;msg, getpid()&amp;gt;) // se il messaggio l'ho ricevuto da un client lo inoltro al server[0]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 19/06/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.06.19.tot.pdf 2017.06.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare)===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define NATLETI n&lt;br /&gt;
&lt;br /&gt;
condition ok2lancia[NATLETI];&lt;br /&gt;
condition ok2giudice;&lt;br /&gt;
&lt;br /&gt;
int counter[NATLETI];&lt;br /&gt;
int ultimo_tiro;&lt;br /&gt;
float registro[NATLETI][3];&lt;br /&gt;
&lt;br /&gt;
Procedure entry: boolean pronto(int i)&lt;br /&gt;
{&lt;br /&gt;
    if(!(i == 0 &amp;amp;&amp;amp; counter[i] == 0)) // se è il primo lancio non devo metterlo in wait&lt;br /&gt;
        ok2lancia[i].wait()&lt;br /&gt;
    if(counter[i] &amp;lt; 3)&lt;br /&gt;
        return true;&lt;br /&gt;
    else&lt;br /&gt;
        return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void lanciato (int i)&lt;br /&gt;
{&lt;br /&gt;
    counter[i]++;&lt;br /&gt;
    ultimo_tiro = i;&lt;br /&gt;
    ok2giudice.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int lanciofatto()&lt;br /&gt;
{&lt;br /&gt;
    ok2giudice.wait()&lt;br /&gt;
    if(ultimo_tiro == NATLETI-1 &amp;amp;&amp;amp; counter[0] == 3)&lt;br /&gt;
        return -1;  // devo invalidare la condizione per uscire dal while, quindi se nessuno deve più lanciare ritorno -1&lt;br /&gt;
    else&lt;br /&gt;
        return ultimo_tiro;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void registraechiama(int i, float m)&lt;br /&gt;
{&lt;br /&gt;
    registro[i][counter[i]-1] = m; // il secondo indice indica l'iesimo lancio -1 (perchè iniziamo a contare da zero)&lt;br /&gt;
    if(i == NATLETI-1) // se ha appena tirato l'ultimo atleta non posso dare il via a NATLETI (perchè non esiste), quindi faccio ricominciare il giro&lt;br /&gt;
        ok2lancia[0].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2lancia[i+1].signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int classifica()&lt;br /&gt;
{&lt;br /&gt;
    int best[NATLETI];&lt;br /&gt;
    for(int i = 0; i &amp;lt; NATLETI; i++)&lt;br /&gt;
    {&lt;br /&gt;
        for(int j = 0; j &amp;lt; 3; j++)&lt;br /&gt;
        {&lt;br /&gt;
            if(registro[i][j] &amp;gt; best[i])&lt;br /&gt;
                best[i] = registro[i][j];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    best.sort_in_descending_order(); // supponiamo nel nostro pseudolinguaggio esista una funzione di ordinamento qualunque&lt;br /&gt;
    return best;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.02.14.tot.pdf 2015.02.14.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
condition ok2red;&lt;br /&gt;
condition ok2blue;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(color_t color, generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if(buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
    if((&amp;lt;color&amp;gt; == buffer.last()) == color)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2red.wait();&lt;br /&gt;
        else&lt;br /&gt;
            ok2blue.wait();&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(&amp;lt;color, val&amp;gt;);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
    if(buffer.lenght() &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2blue.signal();&lt;br /&gt;
        else&lt;br /&gt;
            ok2red.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if(buffer.lenght == 0)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
    &amp;lt;val&amp;gt; = buffer.dequeue();&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 4:       3 4 5 5 5 5 3 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FIFO:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 4 4 4 4 2 2 2 2 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 5 5 5 5 3 3 3 3 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 0 0 0 0 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 3 3 3 1 1 1 1 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 0 1 2 3 0 1 4 2 0 3 4 1 2 3 4&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 4 5 5 5 3 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LRU:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 4 4 4 2 2 2 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 5 5 5 3 3 3 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 3 3 1 1 1 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
Il problema si può risolvere utilizzando l'algoritmo LRU e la seguente stringa di riferimenti:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 4 3 2 1 5 3 2 4 1 5 4 3 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2391</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2391"/>
		<updated>2019-05-24T17:17:06Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 20/01/2015 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// server[] = array contenente il PID di tutti i server&lt;br /&gt;
&lt;br /&gt;
#define BROADCAST server[0]&lt;br /&gt;
&lt;br /&gt;
server[0]&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto da me stesso allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(*, &amp;lt;msg, getpid()&amp;gt;); // se il messaggio l'ho ricevuto da un client o da un altro server lo inoltro a tutti i server (compreso me stesso)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
server[x] // x = 1...N-1&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto dal server[0] allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(BROADCAST, &amp;lt;msg, getpid()&amp;gt;) // se il messaggio l'ho ricevuto da un client lo inoltro al server[0]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.02.14.tot.pdf 2015.02.14.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
condition ok2red;&lt;br /&gt;
condition ok2blue;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(color_t color, generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if(buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
    if((&amp;lt;color&amp;gt; == buffer.last()) == color)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2red.wait();&lt;br /&gt;
        else&lt;br /&gt;
            ok2blue.wait();&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(&amp;lt;color, val&amp;gt;);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
    if(buffer.lenght() &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if(color == red)&lt;br /&gt;
            ok2blue.signal();&lt;br /&gt;
        else&lt;br /&gt;
            ok2red.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if(buffer.lenght == 0)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
    &amp;lt;val&amp;gt; = buffer.dequeue();&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 4:       3 4 5 5 5 5 3 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
FIFO:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 5 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0&lt;br /&gt;
               Frame 1: 0 0 0 0 4 4 4 4 2 2 2 2 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 5 5 5 5 3 3 3 3 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 0 0 0 0 4 4 4 4 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 3 3 3 1 1 1 1 0 0 0 0 0 0 0 0 0 0&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 0 1 2 3 4 0 1 2 3 0 1 4 2 0 3 4 1 2 3 4&lt;br /&gt;
               Frame 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1&lt;br /&gt;
               Frame 2:   1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3&lt;br /&gt;
               Frame 4:       3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 4 5 5 5 3 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LRU:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 4 4 4 2 2 2 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 5 5 5 3 3 3 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 3 3 1 1 1 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
Il problema si può risolvere utilizzando l'algoritmo LRU e la seguente stringa di riferimenti:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 4 3 2 1 5 3 2 4 1 5 4 3 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2390</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2390"/>
		<updated>2019-05-24T10:04:29Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.2 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// server[] = array contenente il PID di tutti i server&lt;br /&gt;
&lt;br /&gt;
#define BROADCAST server[0]&lt;br /&gt;
&lt;br /&gt;
server[0]&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto da me stesso allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(*, &amp;lt;msg, getpid()&amp;gt;); // se il messaggio l'ho ricevuto da un client o da un altro server lo inoltro a tutti i server (compreso me stesso)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
server[x] // x = 1...N-1&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto dal server[0] allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(BROADCAST, &amp;lt;msg, getpid()&amp;gt;) // se il messaggio l'ho ricevuto da un client lo inoltro al server[0]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 4 5 5 5 3 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LRU:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 4 4 4 2 2 2 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 5 5 5 3 3 3 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 3 3 1 1 1 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
Il problema si può risolvere utilizzando l'algoritmo LRU e la seguente stringa di riferimenti:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 4 3 2 1 5 3 2 4 1 5 4 3 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2389</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2389"/>
		<updated>2019-05-24T08:18:35Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// server[] = array contenente il PID di tutti i server&lt;br /&gt;
&lt;br /&gt;
#define BROADCAST server[0]&lt;br /&gt;
&lt;br /&gt;
server[0]&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto da me stesso allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(*, &amp;lt;msg, getpid()&amp;gt;); // se il messaggio l'ho ricevuto da un client o da un altro server lo inoltro a tutti i server (compreso me stesso)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
server[x] // x = 1...N&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto dal server[0] allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(BROADCAST, &amp;lt;msg, getpid()&amp;gt;) // se il messaggio l'ho ricevuto da un client lo inoltro al server[0]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 4 5 5 5 3 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LRU:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 4 4 4 2 2 2 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 5 5 5 3 3 3 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 3 3 1 1 1 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
Il problema si può risolvere utilizzando l'algoritmo LRU e la seguente stringa di riferimenti:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 4 3 2 1 5 3 2 4 1 5 4 3 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2388</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2388"/>
		<updated>2019-05-24T08:18:04Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// server[] = array contenente il PID di tutti i server&lt;br /&gt;
&lt;br /&gt;
#define BROADCAST server[0]&lt;br /&gt;
&lt;br /&gt;
server[0]&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto da me stesso allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(*, &amp;lt;msg, getpid()&amp;gt;); // se il messaggio l'ho ricevuto da un client o da un altro server lo inoltro a tutti i server (compreso me stesso)&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
server[x] // x = 1...N&lt;br /&gt;
{&lt;br /&gt;
    while(true)&lt;br /&gt;
    {&lt;br /&gt;
        &amp;lt;msg, sender&amp;gt; = arecv(*); // ricevo il messaggio&lt;br /&gt;
        if (sender == BROADCAST)&lt;br /&gt;
            print(msg); // se il messaggio l'ho ricevuto dal server[0] allora lo stampo&lt;br /&gt;
        else&lt;br /&gt;
            asend(BROADCAST, &amp;lt;msg, getpid()&amp;gt;) // se il messaggio l'ho ricevuto da un client lo inoltro al server[0]&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 4 5 5 5 3 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LRU:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 4 4 4 2 2 2 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 5 5 5 3 3 3 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 3 3 1 1 1 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
Il problema si può risolvere utilizzando l'algoritmo LRU e la seguente stringa di riferimenti:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 4 3 2 1 5 3 2 4 1 5 4 3 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2387</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2387"/>
		<updated>2019-05-23T16:44:57Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
a)&amp;lt;br&amp;gt;&lt;br /&gt;
MIN:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 2 2 2 2 2 2 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 4 5 5 5 3 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
LRU:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 1 2 3 4 5 1 2 3 4 1 2 3 1 2 1&lt;br /&gt;
               Frame 1: 1 1 1 4 4 4 2 2 2 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   2 2 2 5 5 5 3 3 3 2 2 2 2 2&lt;br /&gt;
               Frame 3:     3 3 3 1 1 1 4 4 4 3 3 3 3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
B)&amp;lt;br&amp;gt;&lt;br /&gt;
Il problema si può risolvere utilizzando l'algoritmo LRU e la seguente stringa di riferimenti:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
Stringa di riferimenti: 4 3 2 1 5 3 2 4 1 5 4 3 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2386</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2386"/>
		<updated>2019-05-23T16:30:08Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 29/05/2017 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 20/01/2015 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2015.01.20.tot.pdf 2015.01.20.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define MAX n&lt;br /&gt;
&lt;br /&gt;
condition ok2read;&lt;br /&gt;
condition ok2write;&lt;br /&gt;
&lt;br /&gt;
queue buffer;&lt;br /&gt;
int waiting_write = 0;&lt;br /&gt;
int waiting_read = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void write(generic_type val)&lt;br /&gt;
{&lt;br /&gt;
    if (buffer.lenght() &amp;gt;= MAX)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&lt;br /&gt;
    buffer.enqueue(val);&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: generic_type read(void)&lt;br /&gt;
{&lt;br /&gt;
    generic_type val;&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
    {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&lt;br /&gt;
        {&lt;br /&gt;
            ok2read.signal();&lt;br /&gt;
        }&lt;br /&gt;
        waiting_read++;&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
        waiting_read--:&lt;br /&gt;
    }&lt;br /&gt;
    if (buffer.lenght() == 0)&lt;br /&gt;
        val = NULL;&lt;br /&gt;
    else&lt;br /&gt;
        val = dequeue;&lt;br /&gt;
    ok2write.signal()&lt;br /&gt;
    return val;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2385</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2385"/>
		<updated>2019-05-23T13:14:33Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio g.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2384</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2384"/>
		<updated>2019-05-22T16:02:46Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 3,3,3     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2383</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2383"/>
		<updated>2019-05-22T13:07:49Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 28/05/2018 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 3,3,3     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Stack&amp;lt;int&amp;gt; entriesStack;&lt;br /&gt;
&lt;br /&gt;
int vid[MAX];&lt;br /&gt;
condition ok2esci[MAX]&lt;br /&gt;
int in = 0; &lt;br /&gt;
int out = -1;&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: entra(int id) {&lt;br /&gt;
    if (in &amp;gt;= MAX)&lt;br /&gt;
        ok2entra.wait()&lt;br /&gt;
    vid[in++] = id;&lt;br /&gt;
    if (in &amp;lt; MAX)&lt;br /&gt;
        ok2entra.signal()&lt;br /&gt;
    else&lt;br /&gt;
        out = MAX - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure-entry: esci(int id) {&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i = 0; i &amp;lt; in; i++)&lt;br /&gt;
        if (vid[i] == id)&lt;br /&gt;
            break; //cerco l'indice di id nel vettore vid&lt;br /&gt;
&lt;br /&gt;
    if (i != out)&lt;br /&gt;
        ok2esci[i].wait();&lt;br /&gt;
&lt;br /&gt;
    if (out &amp;gt; 0) {&lt;br /&gt;
        out--;&lt;br /&gt;
        ok2esci[out].signal();&lt;br /&gt;
    } else {&lt;br /&gt;
        out--;&lt;br /&gt;
        in = 0; &lt;br /&gt;
        ok2entra.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2382</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2382"/>
		<updated>2019-05-22T11:01:34Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 3,3,3     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Monitor riempisvuota {&lt;br /&gt;
    Int MAXPROCESSI;&lt;br /&gt;
    Stack s;&lt;br /&gt;
    condition ok2enter;&lt;br /&gt;
    condition ok2exit;&lt;br /&gt;
 &lt;br /&gt;
    p.e void entra(getPid()){ &lt;br /&gt;
        if( s.size() &amp;gt;= MAXPROCESSI)&lt;br /&gt;
            ok2enter.wait();&lt;br /&gt;
        s.insert(getPid());&lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI)&lt;br /&gt;
            ok2exit.signal() &lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    p.e void esci(getPid()){ &lt;br /&gt;
        if(s.size() &amp;gt; MAXPROCESSI &amp;amp;&amp;amp; s.top == getPid()) {&lt;br /&gt;
            s.pop();&lt;br /&gt;
            ok2entra.signal()&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            ok2exit.wait();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2381</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2381"/>
		<updated>2019-05-22T10:58:15Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 12/02/2018 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 3,3,3     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.05.28.tot.pdf 2018.05.28.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
dovrebbe stampare anche il nome del segnale prima di stampare il tempo ma per il resto va bene&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # caso di file che non riesce ad aprire&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, []) #firstline include anche il carattere \n, quindi quando si stampa va anche a capo&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2376</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2376"/>
		<updated>2019-05-16T11:48:32Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 3,3,3     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
    }&lt;br /&gt;
    isBridgeUp = false;&lt;br /&gt;
    shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);\&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # normale che ci siano molti file che non riesce ad aprire?&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, [])&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2375</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2375"/>
		<updated>2019-05-16T11:46:38Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 12/02/2018 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 3,3,3     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 12/02/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.02.12.tot.pdf 2018.02.12.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shipping[2] = {0, 0}; //navi da entrambe le direzioni&lt;br /&gt;
  int status = NONE; //UP DOWN NONE&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingC = 0;      //coda delle macchine che aspettano&lt;br /&gt;
  int waitingS[2] = {0,0};  //navi che stanno aspettando&lt;br /&gt;
   &lt;br /&gt;
  condition ok2ship[2]&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
 &lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    if(carsOnBridge &amp;gt;= MAX || status == UP || waitingS[0] + waitingS[1] &amp;gt; 0 ){&lt;br /&gt;
        waitingC++;ok2drive.wait;waitingC--;}&lt;br /&gt;
    status = DOWN;&lt;br /&gt;
    carsOnBridge++&lt;br /&gt;
    if (carsOnBridge &amp;lt; MAX)&lt;br /&gt;
       ok2drive.signal();     //vanno tutte le MAX car che stanno aspettando&lt;br /&gt;
} &lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--&lt;br /&gt;
    if (waitingS[0] + waitingS[1] == 0)&lt;br /&gt;
    ok2drive.signal();&lt;br /&gt;
    if(carsOnBridge == 0){&lt;br /&gt;
        ok2ship[0].signal(); ok2ship[1].signal();&lt;br /&gt;
    }&lt;br /&gt;
    if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
    status = NONE&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
if (bridge = DOWN || shipping[direction] != 0 || waitingC &amp;gt; 0)&lt;br /&gt;
   {&lt;br /&gt;
        waitingS[i]++; ok2ship[i].wait(); waitingS[i]--; &lt;br /&gt;
   }&lt;br /&gt;
   isBridgeUp = false;&lt;br /&gt;
   shipping[i] = 1;&lt;br /&gt;
 &lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
      shipping[i] = 0;&lt;br /&gt;
      if (waitingC == 0)&lt;br /&gt;
          ok2ship[i].signal()&lt;br /&gt;
      else if(shipping[1-i] == 0)&lt;br /&gt;
          ok2drive.signal();&lt;br /&gt;
      if(carsOnBridge + waitingS[0] + waitingS[1] == 0) &lt;br /&gt;
      status = NONE&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge&lt;br /&gt;
  condition ok2passCar;&lt;br /&gt;
  condition ok2passBoat;&lt;br /&gt;
  condition ok2up;&lt;br /&gt;
  condition ok2down;&lt;br /&gt;
  int carOnBridge[2] = 0; //2 sensi di marcia&lt;br /&gt;
  int boatUnderBridge[2] = 0;&lt;br /&gt;
  boolean bridge_down = false; //vuol dire che il ponte parte alzato, true ponte abbassato&lt;br /&gt;
  &lt;br /&gt;
  procedure entry car_enter(direction){&lt;br /&gt;
      if(bridge_down &amp;amp;&amp;amp; carOnBridge[direction] &amp;lt; MAXCAR){&lt;br /&gt;
        carOnBridge[direction]++;&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
      }else if (bridge_down &amp;amp;&amp;amp; boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        //se non ci sono navi in transito e arriva una macchina abbassa ponte&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
        ok2passCar.signal();&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }     &lt;br /&gt;
        &lt;br /&gt;
  procedure entry car_exit(direction){&lt;br /&gt;
      carOnBridge[direction]--;&lt;br /&gt;
      if(carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        bridge_down = false;&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2up.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_enter(direction){&lt;br /&gt;
      if(!bridge_down &amp;amp;&amp;amp; boatUnderBridge[direction] &amp;lt; 1){&lt;br /&gt;
        boatUnderBridge[direction]++;&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
      }else if(!bridge_down &amp;amp;&amp;amp; carOnBridge[0] == 0 &amp;amp;&amp;amp; carOnBridge[1] == 0){&lt;br /&gt;
        ok2up.signal();&lt;br /&gt;
        ok2passBoat.signal();&lt;br /&gt;
        ok2passCar.wait();&lt;br /&gt;
      }else {&lt;br /&gt;
        ok2passBoat.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
      &lt;br /&gt;
  procedure entry boat_exit(direction){  &lt;br /&gt;
      boatUnderBridge[direction]--;&lt;br /&gt;
      if(boatUnderBridge[0] == 0 &amp;amp;&amp;amp; boatUnderBridge[1] == 0){&lt;br /&gt;
        bridge_down = true;&lt;br /&gt;
        ok2down.signal();&lt;br /&gt;
      }else{&lt;br /&gt;
        ok2down.wait();&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 2o (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define car 1&lt;br /&gt;
#define ship 2 &lt;br /&gt;
#define fromDX 1&lt;br /&gt;
#define fromSX 0&lt;br /&gt;
&lt;br /&gt;
monitor bridge  {&lt;br /&gt;
  int carsOnBridge = 0;&lt;br /&gt;
  int shippingDX = 0; //nave che sta passando dal lato destro&lt;br /&gt;
  int shippingSX = 0; //nave che sta passando dal lato sinistro&lt;br /&gt;
  bool isBridgeUp = false;&lt;br /&gt;
  int last2pass = 0;     //ultimo che ha passato il ponte&lt;br /&gt;
  int waitingS = 0;  //navi che stanno aspettando&lt;br /&gt;
  int waitingC = 0 ; //auto che stanno aspettando&lt;br /&gt;
  &lt;br /&gt;
  condition ok2ship&lt;br /&gt;
  condition ok2drive&lt;br /&gt;
&lt;br /&gt;
p.e. car_enter(int direction){&lt;br /&gt;
    //un auto si ferma se il numero di auto sul ponte è massimo&lt;br /&gt;
    //e se l'ultima a passare è stata un auto mentre ci sono navi in attesa&lt;br /&gt;
    if(carsOnBridge == MAX || isBridgeUp || (last2pass==car &amp;amp;&amp;amp; waitingS &amp;gt; 0) ){&lt;br /&gt;
        waitingC++;&lt;br /&gt;
        ok2drive.wait;&lt;br /&gt;
    }&lt;br /&gt;
    carsOnBridge++;&lt;br /&gt;
    waitingC--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. car_exit(int direction){&lt;br /&gt;
    carsOnBridge--;&lt;br /&gt;
    last2pass = car;&lt;br /&gt;
    if(carsOnBridge == 0 &amp;amp;&amp;amp; waitingS&amp;gt;0){&lt;br /&gt;
        isBrigdeUp = true;&lt;br /&gt;
        ok2ship.signal;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_enter(int direction){&lt;br /&gt;
    //se la barca viene da destra&lt;br /&gt;
    if(direction == fromDX){&lt;br /&gt;
        //si ferma anche quando c'è una nave che sta già attraversando nella sua stessa direzione&lt;br /&gt;
        if (isBridgeup == false || shippingDX || (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0) ){&lt;br /&gt;
            waitingS++;&lt;br /&gt;
            ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;&lt;br /&gt;
        shippingDX = 1;&lt;br /&gt;
        }&lt;br /&gt;
    //se la barca viene da sinistra&lt;br /&gt;
    else if(direction == fromSX){&lt;br /&gt;
        if (isBridgeup == false || shippingSX || ( (last2pass==ship &amp;amp;&amp;amp; waitingC &amp;gt; 0))){&lt;br /&gt;
        waitingS++;&lt;br /&gt;
        ok2ship.wait;&lt;br /&gt;
        }&lt;br /&gt;
        if (waitingS &amp;gt; 0)&lt;br /&gt;
            waitingS--;        &lt;br /&gt;
        shippingSX = 1;&lt;br /&gt;
    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
p.e. ship_exit(int direction){&lt;br /&gt;
        if(direction == fromDX)&lt;br /&gt;
            shippingDX = 0;&lt;br /&gt;
        else if (direction == fromSX)&lt;br /&gt;
            shippingSX = 0;&lt;br /&gt;
        last2pass = ship;&lt;br /&gt;
        if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingC)&lt;br /&gt;
            isBrigdeUp == false;&lt;br /&gt;
            ok2drive.signal;&lt;br /&gt;
        else if(shippingDX == 0 &amp;amp;&amp;amp; shippingSX == 0 &amp;amp;&amp;amp; waitingS &amp;gt; 0)&lt;br /&gt;
            ok2ship.signal;    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 11/09/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor crossing&lt;br /&gt;
&lt;br /&gt;
ok2dir[4];     //NESW&lt;br /&gt;
bool busy = false;&lt;br /&gt;
&lt;br /&gt;
pe entra(int dir)&lt;br /&gt;
   if (busy)&lt;br /&gt;
      ok2dir[dir].wait();&lt;br /&gt;
   busy = true;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   ok2dir[(dir + 1) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 2) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 3) % 4].signal();&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + 4) % 4].signal();  //dir&lt;br /&gt;
&lt;br /&gt;
//alternativa più compatta&lt;br /&gt;
pe esci(int dir)&lt;br /&gt;
   busy = false;&lt;br /&gt;
   for (i = 0; i &amp;lt; 4; i++)&lt;br /&gt;
   if (!busy)&lt;br /&gt;
      ok2dir[(dir + i + 1) % 4].signal();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
== Esame 17/07/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.07.17.tot.pdf 2017.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor conf {&lt;br /&gt;
        condition finished;&lt;br /&gt;
        condition ready2present[max];&lt;br /&gt;
        bool arrived[max] = false;&lt;br /&gt;
        bool giachiamato[max] = false;&lt;br /&gt;
&lt;br /&gt;
        p.e. chiama(chiamato){&lt;br /&gt;
        if(arrived[chiamato] == true)&lt;br /&gt;
                ready2present[chiamato].signal;&lt;br /&gt;
                finished.wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        else&lt;br /&gt;
                giachiamato[chiamato]= true&lt;br /&gt;
                return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. arrivato(nome){&lt;br /&gt;
                if(giachiamato[nome] == true)&lt;br /&gt;
                        return  false;&lt;br /&gt;
&lt;br /&gt;
                arrived[nome] = true;&lt;br /&gt;
                ok2present[nome].wait;&lt;br /&gt;
                return true;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        p.e. finepresentazione(nome){&lt;br /&gt;
                finished.signal;&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
casi da discutere:    &lt;br /&gt;
se arrivano studenti a pronto prima che il prof dichiara nuovapartita succedono guai.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&amp;lt;source lang=html5&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Esame Pratico 21/09/2018 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf&lt;br /&gt;
=== Esercizio 1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
       #define _GNU_SOURCE&lt;br /&gt;
       #include &amp;lt;sys/signalfd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;signal.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;time.h&amp;gt;&lt;br /&gt;
       #include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char * argv[]){&lt;br /&gt;
        sigset_t mask;&lt;br /&gt;
        struct signalfd_siginfo fdsi;&lt;br /&gt;
        int fd;&lt;br /&gt;
        char* t;&lt;br /&gt;
        char* filename;&lt;br /&gt;
&lt;br /&gt;
        sigemptyset(&amp;amp;mask);\&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR1);&lt;br /&gt;
        sigaddset(&amp;amp;mask, SIGUSR2);&lt;br /&gt;
        sigprocmask(SIG_SETMASK, &amp;amp;mask, NULL);&lt;br /&gt;
&lt;br /&gt;
        int sigfd = signalfd(-1, &amp;amp;mask, 0);&lt;br /&gt;
&lt;br /&gt;
        for(;;){&lt;br /&gt;
                read(sigfd, &amp;amp;fdsi, sizeof(struct signalfd_siginfo));&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR1){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                if(fdsi.ssi_signo == SIGUSR2){&lt;br /&gt;
                        asprintf(&amp;amp;filename, &amp;quot;./%u&amp;quot;, fdsi.ssi_pid);&lt;br /&gt;
                        fd = open(filename, O_APPEND | O_CREAT | O_WRONLY);&lt;br /&gt;
                        time_t stime = time(NULL);&lt;br /&gt;
                        t = ctime(&amp;amp;stime);&lt;br /&gt;
                        write(fd, t, sizeof(char)*strlen(t));&lt;br /&gt;
                        close(fd);&lt;br /&gt;
                        }&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 3 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
import sys&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
dict = {}&lt;br /&gt;
&lt;br /&gt;
def func(a):&lt;br /&gt;
    os.chdir(a)&lt;br /&gt;
    for root, dirs, files in os.walk(&amp;quot;.&amp;quot;):&lt;br /&gt;
      for filename in files:&lt;br /&gt;
        try:&lt;br /&gt;
          fl =file(filename)&lt;br /&gt;
          firstline = fl.readline()&lt;br /&gt;
          fl.close()&lt;br /&gt;
        except IOError: # normale che ci siano molti file che non riesce ad aprire?&lt;br /&gt;
          #print(&amp;quot;could not read&amp;quot;, file)&lt;br /&gt;
          pass&lt;br /&gt;
        if (re.match('^#!', firstline)):&lt;br /&gt;
          dict.setdefault(firstline, [])&lt;br /&gt;
          dict[firstline].append(filename)&lt;br /&gt;
    for k in dict.keys():&lt;br /&gt;
      print k&lt;br /&gt;
      for v in dict[k]:&lt;br /&gt;
        print v&lt;br /&gt;
      #print(&amp;quot; &amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
  if (len(sys.argv)==1):&lt;br /&gt;
    dir = &amp;quot;.&amp;quot;&lt;br /&gt;
  else:&lt;br /&gt;
    dir = sys.argv[1]&lt;br /&gt;
  func(dir)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=User:Mattiabiondi&amp;diff=2352</id>
		<title>User:Mattiabiondi</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=User:Mattiabiondi&amp;diff=2352"/>
		<updated>2019-05-07T14:54:42Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: Created page with &amp;quot;nothing to see here&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;nothing to see here&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2347</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2347"/>
		<updated>2019-05-02T13:31:58Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio g.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2346</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2346"/>
		<updated>2019-05-02T13:09:52Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.2 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2345</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2345"/>
		<updated>2019-05-02T13:05:48Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio g.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Minimizzato&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 4,4,4     //massimo&lt;br /&gt;
COH = 1,1,1    //soldi in cassa&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES  &lt;br /&gt;
P1 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P2 | 3,3,3 | 1,1,1 | 2,2,2&lt;br /&gt;
P3 | 3,3,3 | 1,1,1 | 2,2,2&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2344</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2344"/>
		<updated>2019-05-02T12:50:15Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2343</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2343"/>
		<updated>2019-05-02T12:47:37Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    V() {&lt;br /&gt;
        if (value &amp;gt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmax.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value++;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2342</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2342"/>
		<updated>2019-05-02T12:36:50Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue of semaphore okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    init(x) : { value=x; }&lt;br /&gt;
    P() {&lt;br /&gt;
        if (value &amp;lt;= -N)  {&lt;br /&gt;
            s=semaphore(0);&lt;br /&gt;
            okmin.enqueue(s);&lt;br /&gt;
            mutex.V();&lt;br /&gt;
            s.P();&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
        } else {&lt;br /&gt;
            value--;&lt;br /&gt;
            mutex.V();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2341</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2341"/>
		<updated>2019-05-02T12:35:58Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.2 (sbagliato) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2340</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2340"/>
		<updated>2019-05-02T12:35:15Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.2 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soluzione &amp;quot;schiacciasassi&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2339</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2339"/>
		<updated>2019-05-02T12:26:38Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.2 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
Soluzione &amp;quot;furba e facile&amp;quot;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
class lim_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   //serve per significato&lt;br /&gt;
    &lt;br /&gt;
    init(x) : { value=x; plus.init(N+x); minus.init(N-x);}   //costruttore&lt;br /&gt;
    P() : { plus.P(); value--; minus.V(); }&lt;br /&gt;
    V() : { minus.P(); value++; plus.V(); }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2338</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2338"/>
		<updated>2019-05-02T12:04:03Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard--;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2337</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2337"/>
		<updated>2019-05-02T11:53:21Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define NONE 0&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onboard--; onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2336</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2336"/>
		<updated>2019-05-02T11:39:13Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
#define NONE 0&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
condition mutex; // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int onramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onboard--; onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2335</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2335"/>
		<updated>2019-05-02T11:38:21Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 (sbagliato) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
 &lt;br /&gt;
#define MAX n&lt;br /&gt;
#define TERRAFERMA 1&lt;br /&gt;
#define ISOLA 2&lt;br /&gt;
#define NONE 0&lt;br /&gt;
 &lt;br /&gt;
condition ok2unload;&lt;br /&gt;
condition ok2load[2];&lt;br /&gt;
condition ok2ship;&lt;br /&gt;
condition empty;&lt;br /&gt;
condition mutex; // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
 &lt;br /&gt;
int onboard = 0;&lt;br /&gt;
int nramp = 0;&lt;br /&gt;
int current_port = NONE;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    //arrivando&lt;br /&gt;
    current_port = location;&lt;br /&gt;
    ok2unload.signal();&lt;br /&gt;
    if (onboard &amp;gt; 0)&lt;br /&gt;
        empty.wait()&lt;br /&gt;
    ok2load[location].signal()&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2ship.wait()&lt;br /&gt;
    //partendo&lt;br /&gt;
    current_port = NONE;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0 || onboard &amp;gt;= MAX)&lt;br /&gt;
        ok2load[location].wait()&lt;br /&gt;
    onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0; onboard++;&lt;br /&gt;
    if (onboard &amp;lt; MAX)&lt;br /&gt;
        ok2load[location].signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    if (current_port != location || onramp &amp;gt; 0)&lt;br /&gt;
        ok2unload.wait()&lt;br /&gt;
    onboard--; onramp = 1;&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    onramp = 0;&lt;br /&gt;
    if (onboard == 0)&lt;br /&gt;
        empty.signal();&lt;br /&gt;
    else&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2334</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2334"/>
		<updated>2019-05-02T11:25:07Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2333</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2333"/>
		<updated>2019-05-02T11:24:39Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: Undo revision 2332 by Renzo (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2331</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2331"/>
		<updated>2019-04-29T10:20:58Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio g.2 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10&lt;br /&gt;
COH = 4,4,4&lt;br /&gt;
 &lt;br /&gt;
      MAX     ATT     RES    AVAIL&lt;br /&gt;
P1 | 6,6,6 | 1,1,1 | 5,5,5 | 4,4,4&lt;br /&gt;
P2 | 6,6,6 | 1,1,1 | 5,5,5 | 5,5,5&lt;br /&gt;
P3 | 9,9,9 | 4,4,4 | 5,5,5 | 6,6,6&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2330</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2330"/>
		<updated>2019-04-28T18:18:56Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 16/07/2014 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2329</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2329"/>
		<updated>2019-04-28T18:17:54Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 29/05/2017 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2017.05.29.tot.pdf 2017.05.29.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2328</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2328"/>
		<updated>2019-04-28T18:16:56Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 21/06/2018 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.06.21.tot.pdf 2018.06.21.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2327</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2327"/>
		<updated>2019-04-28T18:16:03Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 17/07/2018 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.07.17.tot.pdf 2018.07.17.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2326</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2326"/>
		<updated>2019-04-28T18:14:59Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 19/09/2018 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf 2018.09.19.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2325</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2325"/>
		<updated>2019-04-28T18:11:56Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.2 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) L'algoritmo di calcolo del working set serve a limitare il problema del trashing assicurandosi che le pagine di cui ha bisogno un processo (una loro approssimazione) siano già caricate in memoria prima di far partire il processo stesso. L'algoritmo viene eseguito ogni volta che avviene un page fault, cercando una pagina &amp;quot;vittima&amp;quot; non presente nel working set e sfrattandola, facendo posto alla pagina che occorre al processo in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
b) La lunghezza massima di un file che può essere memorizzato su un file system di tipo FAT viene calcolata moltiplicando il massimo numero di cluster (dimensione dell'unità di allocazione) identificabili per la loro dimensione. Il massimo numero di cluster identificabili dipende da quanti bit sono allocati per numerarli, e per questa distinzione esistono varie versioni di FAT (FAT12, FAT16, FAT32).&amp;lt;br&amp;gt;&lt;br /&gt;
FAT32 memorizza la dimensione dei file in un intero unsigned da 32bit, e non può quindi gestire un file di dimensione superiore ai 2^32 bit = ~4GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT16, allocando 16bit per identificare i cluster, può contarne al massimo 2^16 (65536). Prendendo quindi, ad esempio, un file system FAT16 con cluster da 32KB, possiamo avere file grandi al massimo 32KB*65536 = ~2GB.&amp;lt;br&amp;gt;&lt;br /&gt;
FAT12 di conseguenza può numerare al massimo 2^12 (4096) cluster, ma dato che il numero dei settori del disco viene memorizzato in un intero signed a 16bit, la massima dimensione del disco è 2^15 = 32MB. Ovviamente, non si può memorizzare un file di grandezza superiore alla dimensione dell'unità di memorizzazione stessa, e quindi anche i file in FAT12 possono avere dimensione massima di 32MB.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Un virus necessità l'intervento umano per essere avviato o per essere diffuso. Si attacca a programmi o file per potersi diffondere. Un worms è in grado di riprodursi e di diffondersi autonomamente, sfruttando le informazioni presenti sul computer.&amp;lt;br&amp;gt;&lt;br /&gt;
d) La ready queue di uno scheduler può essere vuota quando tutti i processi sono in esecuzione su diversi processori, oppure quando tutti i processi hanno terminato la loro esecuzione. È un caso fisiologico della vita di un sistema.&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2324</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2324"/>
		<updated>2019-04-25T09:09:52Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define N n // limite operazioni&lt;br /&gt;
semaphore mutex(1); // sezione critica&lt;br /&gt;
&lt;br /&gt;
class unsigned_semaphore()&lt;br /&gt;
{&lt;br /&gt;
    unsigned int value;&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    &lt;br /&gt;
    P()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;lt; N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;gt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                plus.P();&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                minus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value--;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    V()&lt;br /&gt;
    {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
        if(value &amp;gt; -N)&lt;br /&gt;
        {&lt;br /&gt;
            if (value &amp;lt;= 0)&lt;br /&gt;
            {&lt;br /&gt;
                minus.P();&lt;br /&gt;
            } &lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                plus.V();&lt;br /&gt;
            }&lt;br /&gt;
            value++;&lt;br /&gt;
        }&lt;br /&gt;
        mutex.V();        &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2323</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2323"/>
		<updated>2019-04-24T16:17:05Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2322</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2322"/>
		<updated>2019-04-24T16:16:31Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esame 29/05/2017 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 21/06/2018 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor tmon */&lt;br /&gt;
&lt;br /&gt;
define MAX n;&lt;br /&gt;
define TERRAFERMA 1;&lt;br /&gt;
define ISOLA 2;&lt;br /&gt;
&lt;br /&gt;
semaphore ok2unload;&lt;br /&gt;
semaphore ok2load;&lt;br /&gt;
semaphore ok2ship;&lt;br /&gt;
semaphore mutex(1); // la rampa è zona critica --&amp;gt; mutua esclusione&lt;br /&gt;
&lt;br /&gt;
stack ferry;&lt;br /&gt;
int current_port = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: al_porto(int location)&lt;br /&gt;
{&lt;br /&gt;
    current_port = location; // traghetto arriva a destinazione&lt;br /&gt;
    ok2unload.signal(); // da il via per far sbarcare le macchine&lt;br /&gt;
    ok2ship.wait(); // si ferma&lt;br /&gt;
    current_port = 0; // traghetto sta viaggiando tra i due porti&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.push(1); // sale sul traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: imbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == MAX) // se il traghetto è pieno da il via per farlo salpare&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2ship.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarca(int location)&lt;br /&gt;
{&lt;br /&gt;
    mutex.wait(); // prende possesso della rampa&lt;br /&gt;
    ferry.pop(); // scende dal traghetto&lt;br /&gt;
    mutex.signal(); // libera la rampa&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: sbarcato(int location)&lt;br /&gt;
{&lt;br /&gt;
    if(ferry.lenght() == 0) // se il traghetto è vuoto da il via per far imbarcare le macchine&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2321</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2321"/>
		<updated>2019-04-21T15:35:32Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio g.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Nei sistemi embedded o in computer ad uso specifico in cui sono richiesti tempi di risposta molto rapidi. La memoria virtuale può generare ritardi imprevedibili e può richiedere un supporto hardware per la traduzione da indirizzi virtuali ad indirizzi fisici. Ma in sistemi embedded non sempre c'è spazio fisico per implementare questi supporti hardware.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Perchè ad esempio sulle chiavette USB quasi mai abbiamo il problema di dover utilizzare file di dimensione maggiore ai 4GB. Non utilizza il journaling, che richiede molteplici scritture per ogni azione ed in dispositivi portatili può ridurre di molto la durata. Non supporta i permessi sui file, e questo è un vantaggio per le chiavette USB, pensate per trasferire dati tra PC diversi.&amp;lt;br&amp;gt; &lt;br /&gt;
c) Serve ad aumentare le performance, rendere il sistema resiliente alla perdita di uno o più dischi e poterli rimpiazzare senza interrompere il servizio. RAID serve per tutelarsi dai problemi hardware, non sostituisce i backup in quanto ci permette solo di proseguire il lavoro, non ci permette di recuperare file cancellati o bloccati da ransomware.&amp;lt;br&amp;gt;&lt;br /&gt;
d) Per dimostrare questo occorre una variante del grafo di Holt, detto grafo Wait-For, che si costruisce eliminando i nodi di tipo risorsa e collassando gli archi appropriati, per cui il grafo di Holt contiene un ciclo se e solo se il grafo Wait-For contiene un ciclo e pertanto si ha l'attesa circolare (deadlock).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2320</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2320"/>
		<updated>2019-04-21T14:37:43Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.2 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Possiamo notare subito che il sistema ha due processori ed un dispositivo di I/O.&lt;br /&gt;
'''A''' e '''B''' partono insieme al tempo 0.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' parte tra il tempo 0 ed il tempo 2 (non possiamo sapere di preciso quando perchè entrambe le CPU sono occupate).&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' parte tra il tempo 0 ed il tempo 3.&amp;lt;br&amp;gt;&lt;br /&gt;
A questo punto possiamo supporre che tutti e 4 i processi partano in sequenza ('''A''', '''B''', '''C''', '''D''') nello stesso momento, e ognuno prende la prima CPU libera che trova.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' lavora per 3ms, poi scade il time slice.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel frattempo '''B''' lavora per 2ms, poi richiede I/O per 4ms.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavora '''B''' quindi si libera, e si manda in esecuzione il processo '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Scaduto il time slice per '''A''', si da il controllo ad un nuovo processo. '''B''' è occupato con I/O, '''C''' sta già lavorando, quindi è il turno di '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi richiede I/O per 3ms, che però è occupato da '''B''', quindi si mette in coda per utilizzarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU su cui lavorava '''C''' si libera ed il controllo torna ad '''A''', che doveva lavorare ancora per 2ms prima di chiedere il controllo di I/O, quindi lavora e si mette in coda dietro a '''C'''.&amp;lt;br&amp;gt;&lt;br /&gt;
Tornando a '''D''', questo lavora per 3ms prima che scada il time slice. Anche '''B''' ha finito il lavoro e ha bisogno di una CPU.&amp;lt;br&amp;gt;&lt;br /&gt;
In questo momento sia '''D''' che '''B''' sono nella coda dei processi in stato ready, ma dal diagramma possiamo notare che il controllo torna a '''D'''.&amp;lt;br&amp;gt;&lt;br /&gt;
La CPU ha scelto a caso un processo tra i due, perchè arrivati a questo punto possiamo supporre che lo scheduler sia Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' prende possesso della prima CPU che si libera, ovvero quella occupata da '''A''', poi lavora per 2ms e termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
Nel momento in cui '''B''' termina il lavoro, scade anche il time slice per '''D''', e '''C''' termina di usare I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
Abbiamo due processi ('''C''' e '''D''') in coda ready. Ma abbiamo anche due CPU libere, perchè '''A''' è in coda per I/O e ci entra appena '''C''' finisce di usarlo.&amp;lt;br&amp;gt;&lt;br /&gt;
Lo scheduler sceglie di mandare '''C''' sul primo processore e '''D''' sul secondo.&amp;lt;br&amp;gt;&lt;br /&gt;
'''A''' nel frattempo, lavora per 4ms con I/O.&amp;lt;br&amp;gt;&lt;br /&gt;
'''C''' lavora per 3ms, poi termina il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 3ms, poi scade il time slice. Ci sono due processori liberi, quindi '''D''' riparte subito in esecuzione.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' doveva lavorare ancora per 1ms prima di aver bisogno di I/O, quindi finisce e si mette in coda.&amp;lt;br&amp;gt;&lt;br /&gt;
Ma nello stesso momento '''A''' termina di usare I/O, si prende un processore libero e lavora per i suoi ultimi 2ms.&amp;lt;br&amp;gt;&lt;br /&gt;
'''D''' lavora per 1ms con I/O, poi prende il secondo processore libero e lavora per 1ms prima di terminare il suo lavoro.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Il time slice è di 3ms, lo scheduler è di tipo Round-Robin.&amp;lt;br&amp;gt;&lt;br /&gt;
Il dispositivo di I/O è FIFO. L'ordine con cui partono i processi è quello alfabetico.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
A(){&lt;br /&gt;
    compute_a1(); // 5ms&lt;br /&gt;
    io_a(); // 4ms&lt;br /&gt;
    compute_a2(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
B(){&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
    io_b(); // 4ms&lt;br /&gt;
    compute_b(); // 2ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
C(){&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
    io_c(); // 3ms&lt;br /&gt;
    compute_c(); // 3ms&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
D(){&lt;br /&gt;
    compute_d1(); // 10ms&lt;br /&gt;
    io_d(); // 1ms&lt;br /&gt;
    compute_d2(); // 1ms&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Lo scheduler potrebbe anche essere a priorità:&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''B''' &amp;lt; priorità '''D''' &amp;lt; priorità '''C'''&amp;lt;br&amp;gt;&lt;br /&gt;
Priorità '''A''' = ?&amp;lt;br&amp;gt;&lt;br /&gt;
'''B''' fatto partire prima di '''C''' e '''D'''.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2319</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2319"/>
		<updated>2019-04-20T20:09:16Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio c.1 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack s;&lt;br /&gt;
semaphore mutex(1); // mutua esclusione&lt;br /&gt;
semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void push(int value)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    s.push(value)&lt;br /&gt;
    mutex.V()&lt;br /&gt;
    ok2consume.V()&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int pop()&lt;br /&gt;
{&lt;br /&gt;
    int value;&lt;br /&gt;
    ok2consume.P();&lt;br /&gt;
    mutex.P();&lt;br /&gt;
    value = s.pop();&lt;br /&gt;
    mutex.V();&lt;br /&gt;
    return value;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2318</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2318"/>
		<updated>2019-04-20T13:43:22Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio g.2 (da controlalre) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2317</id>
		<title>Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2317"/>
		<updated>2019-04-17T13:48:07Z</updated>

		<summary type="html">&lt;p&gt;Mattiabiondi: /* Esercizio g.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina serve a raccogliere prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review.&lt;br /&gt;
&lt;br /&gt;
== Esame 19/09/2018 ==&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Condition: MAX&lt;br /&gt;
// Condition: ok2load&lt;br /&gt;
// Condition: ok2unload&lt;br /&gt;
// Condition: ok2move&lt;br /&gt;
&lt;br /&gt;
int airport_codes = [BLQ, CDG, BRX, LGW, FCO, ...]&lt;br /&gt;
struct luggage {&lt;br /&gt;
    int dstcode;&lt;br /&gt;
    int owner;&lt;br /&gt;
};&lt;br /&gt;
luggage cart[MAX];&lt;br /&gt;
int loaded = 0;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void cartat(int code)&lt;br /&gt;
{&lt;br /&gt;
    if(code == 0)&lt;br /&gt;
    {&lt;br /&gt;
        ok2unload.wait();&lt;br /&gt;
        ok2load.signal();&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        ok2load.wait();&lt;br /&gt;
        ok2unload.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void load(int dstcode, int owner)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    if(loaded &amp;lt; MAX)&lt;br /&gt;
    {&lt;br /&gt;
        luggage l;&lt;br /&gt;
        l.dstcode = dstcode;&lt;br /&gt;
        l.owner = owner;&lt;br /&gt;
        cart.push(l);&lt;br /&gt;
        loaded++;&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: int unload(int dstcode)&lt;br /&gt;
{&lt;br /&gt;
    ok2move.wait();&lt;br /&gt;
    int i;&lt;br /&gt;
    for(i=0; i&amp;lt;loaded; i++)&lt;br /&gt;
    {&lt;br /&gt;
        if(cart[i].dstcode == dstcode)&lt;br /&gt;
        {&lt;br /&gt;
            int owner = cart[i].owner;&lt;br /&gt;
            cart[i].remove();&lt;br /&gt;
            loaded--;&lt;br /&gt;
            return owner;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else ok2move.signal();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor dispatch&lt;br /&gt;
condition go_cart;&lt;br /&gt;
condition ok2station; // quando la stazione può caricare&lt;br /&gt;
current_station = None&lt;br /&gt;
// dizionario con chiave destinazione&lt;br /&gt;
luggages = {}&lt;br /&gt;
&lt;br /&gt;
def countl(luggages):&lt;br /&gt;
    n=0&lt;br /&gt;
    for d in luggages:&lt;br /&gt;
        n += len(luggages[d]);&lt;br /&gt;
&lt;br /&gt;
p.e. cartat(code):&lt;br /&gt;
    current_station = code // carrello arriva alla stazione&lt;br /&gt;
    if (code == BLQ || len(luggages[code]) &amp;gt; 0):&lt;br /&gt;
        ok2station[code].signal()&lt;br /&gt;
        go_cart.wait()&lt;br /&gt;
    current_station = None // il carrello sta viaggiando tra le stazioni&lt;br /&gt;
&lt;br /&gt;
p.e. load(dst, owner):&lt;br /&gt;
    if (current_station != BLQ || countl(luggages) &amp;gt;= MAX):&lt;br /&gt;
        ok2station(BLQ).wait()&lt;br /&gt;
    luggages[dst].append(owner)&lt;br /&gt;
    if (countl(luggages) &amp;gt;= MAX)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    &lt;br /&gt;
p.e. unload(dst):&lt;br /&gt;
    if (current_station != dst || len(luggages[dst]) == 0)&lt;br /&gt;
    // lunghezza lista dei bagagli con questa destinazione&lt;br /&gt;
        ok2station(dst).wait()&lt;br /&gt;
    owner = luggages[dst].pop()&lt;br /&gt;
    if len(luggages[dst]) == 0)&lt;br /&gt;
        go_cart.signal()&lt;br /&gt;
    return owner&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* MP sincrono dato quello asincrono */&lt;br /&gt;
&lt;br /&gt;
void ssend(obj msg, process q)&lt;br /&gt;
{&lt;br /&gt;
    asend(msg, q);&lt;br /&gt;
    ack = areceive(q);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
obj sreceive(process p)&lt;br /&gt;
{&lt;br /&gt;
    obj msg = areceive(p);&lt;br /&gt;
    asend(ack, p);&lt;br /&gt;
    return msg;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Soluzione:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
dati asend/arecv devo implementare lssend lsrecv&lt;br /&gt;
&lt;br /&gt;
lssend(dst, msg):&lt;br /&gt;
    asend(dst, (MSG, myid(), msg))&lt;br /&gt;
    arecv(dst)&lt;br /&gt;
&lt;br /&gt;
lsrecv(snd):&lt;br /&gt;
    asend(myid(), (TAG, myid(), NULL))    // mi mando un messaggio che riesco a riconoscere&lt;br /&gt;
    while True:&lt;br /&gt;
        (T, s, m) =  arecv(ANY)           // continua a ricevere finchè non ricevi il mio messaggio&lt;br /&gt;
        if (T != TAG) data.push(s, m)&lt;br /&gt;
        else break&lt;br /&gt;
    while (((s,m) = data.pop(snd) == NULL):   // c'è il messaggio di src definito?&lt;br /&gt;
        (T, s, m) =  arecv(ANY)&lt;br /&gt;
        data.push(s, m)&lt;br /&gt;
    asend(s, (ACK, myid(), NULL)&lt;br /&gt;
    return m&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (sbagliato) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
x = long_compute()/short_compute()&lt;br /&gt;
X = io()&lt;br /&gt;
&lt;br /&gt;
   0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8&lt;br /&gt;
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2&lt;br /&gt;
P1 |x|x|x|x|x|X|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|x|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|-|-|&lt;br /&gt;
P2         |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|x|-|-|&lt;br /&gt;
P3               |-|-|x|x|x|-|-|-|-|-|-|x|x|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|X|X|X|-|-|-|-|-|-|X|X|x|-|-|-|-|-|-|x|x|x|-|-|-|-|-|-|x|-|-|-|-|-|-|-|-|X|X|X|-|-|-|X|X|x|x|&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
P1(start=0): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P2(start=4): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
P3(start=7): 5ms CPU, 5ms IO, 5ms CPU, 5ms IO, 2ms CPU&lt;br /&gt;
&lt;br /&gt;
 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 &lt;br /&gt;
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 &lt;br /&gt;
P|1 1 1|1 1|2 2 2|3 3 3|2 2|1 1 1|3 3|1 1|2 2 2*3 3 3|2 2|3 3|1 1|-|2 2|- - -|3 3|&lt;br /&gt;
I          |1 1 1 1 1|     |2 2 2 2 2|3 3 3 3 3|1 1 1 1 1|2 2 2 2 2|3 3 3 3 3|&lt;br /&gt;
&lt;br /&gt;
r - - - - 2 - - 3 2 2 2 1 1 3 3 3 1 1 2 2 - - - 2 2 2 3 3 1 1&lt;br /&gt;
                      1 3 3&lt;br /&gt;
&lt;br /&gt;
* 3 ha finito input output e 2 è ancora in esecuzione quindi c'è da scegliere&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controlalre) ===&lt;br /&gt;
a) Può richiedere supporto hardware. Se implementato con contatori o stack questi devono essere aggiornati ad ogni riferimento alla memoria. L'intero sistema viene appesantito e rallentato.&amp;lt;br&amp;gt;&lt;br /&gt;
b) Il journaling si assicura che i dati sul filesystem siano consistenti, ma non aggiornati. Assicura la coerenza dei dati, ma non la perdita dei file se il filesystem si danneggia.&amp;lt;br&amp;gt;&lt;br /&gt;
c) Si dice che un programma A ha lo stesso potere espressivo di un programma B quando è possibile esprimere ogni programma scritto con B mediante A. Per implementare MP sincrono dato quello asincrono basta aggiungere una libreria. Per implementare MP asincrono dato quello sincrono bisogna aggiungere un processo server.&amp;lt;br&amp;gt;&lt;br /&gt;
d) In questi casi tutte le istruzioni vengono eseguite con la massima autorità, con problemi di sicurezza nel caso un utente estraneo prenda il controllo del sistema o rischio di commettere gravi errori semplicemente sbagliando a digitare un comando.&lt;br /&gt;
&lt;br /&gt;
== Esame 17/07/2018 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Delirum: */&lt;br /&gt;
&lt;br /&gt;
// Condition: Ok2Load;&lt;br /&gt;
// Condition: Ok2Pour[]; // Un elemento per Type&lt;br /&gt;
int availableBeer[]; // Un elemento per Type &lt;br /&gt;
Queue requests[]; // Un elemento per Type&lt;br /&gt;
Queue pendingRequests;&lt;br /&gt;
&lt;br /&gt;
Procedure entry: void Pour(Type t, Quantity c)&lt;br /&gt;
{&lt;br /&gt;
    if (c &amp;gt; availableBeer[t]) // Richiesta maggiore della birra disponibile&lt;br /&gt;
    {&lt;br /&gt;
        c -= availableBeer[t];&lt;br /&gt;
        availableBeer[t] = 0;              &lt;br /&gt;
        requests[t].Enqueue(c);&lt;br /&gt;
        if (requests[t].Length == 1) // Risveglio un magazziniere solo se è la prima richiesta di questo tipo di birra&lt;br /&gt;
        {&lt;br /&gt;
            pendingRequests.Enqueue(t);&lt;br /&gt;
            Ok2Load().Signal();&lt;br /&gt;
        }&lt;br /&gt;
        Ok2Pour[t].Wait();&lt;br /&gt;
        requests[t].Dequeue(); // Quando ho ottenuto la birra che voglio, elimino la mia richiesta&lt;br /&gt;
    }&lt;br /&gt;
    availableBeer[t] -= c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Type isEmpty()&lt;br /&gt;
{&lt;br /&gt;
    if (pendingRequests.Length == 0)&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Load.Wait();&lt;br /&gt;
    }&lt;br /&gt;
    return pendingRequests.Dequeue();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Procedure entry: Loaded(Type t, Capacity c)&lt;br /&gt;
{&lt;br /&gt;
    availableBeer[t] += c;&lt;br /&gt;
    while (requests[t].Length &amp;gt; 0 &amp;amp;&amp;amp; availableBeer[t] &amp;gt; requests[t].head())&lt;br /&gt;
    {&lt;br /&gt;
        Ok2Pour[t].Signal();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (requests[t].Length &amp;gt; 0) // serve per evitare che a causa di un magazziniere lento si accodino cosi tante richieste che mentre si sta caricando si svuota subito il fusto&lt;br /&gt;
    {&lt;br /&gt;
        pendingRequests.Enqueue(t);&lt;br /&gt;
        Ok2Load.Signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 29/05/2017 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
condition okpartita&lt;br /&gt;
condition ok2chiama&lt;br /&gt;
condition ok2punteggio&lt;br /&gt;
condition ok2run[2][MAX]&lt;br /&gt;
int numpronti&lt;br /&gt;
int punteggio[2]&lt;br /&gt;
boolean partita=false&lt;br /&gt;
boolean partitafinita=false&lt;br /&gt;
chiamati = []&lt;br /&gt;
contabandiera[2]&lt;br /&gt;
int winner&lt;br /&gt;
&lt;br /&gt;
p.e. nuovapartita():&lt;br /&gt;
{&lt;br /&gt;
    punteggio[A] = punteggio[B] = 0;&lt;br /&gt;
    numpronti = 0;&lt;br /&gt;
    partita=true;&lt;br /&gt;
    okpartita.signal()&lt;br /&gt;
    chiamati = [];&lt;br /&gt;
}&lt;br /&gt;
p.e. chiama(l):&lt;br /&gt;
{&lt;br /&gt;
    if (numpronti&amp;lt;2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.wait();&lt;br /&gt;
    }&lt;br /&gt;
    chiamati = l;&lt;br /&gt;
    contabandiera[A] = contabandiera[B] = 0&lt;br /&gt;
    winner = -1;&lt;br /&gt;
    for (s in n)&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[A][s].signal();&lt;br /&gt;
        ok2run[B][s].signal()&lt;br /&gt;
    }&lt;br /&gt;
    ok2punteggio.wait();&lt;br /&gt;
    punteggio[winner++]&lt;br /&gt;
    if (max(punteggio) == 10)&lt;br /&gt;
    {&lt;br /&gt;
        partitafinita = true;&lt;br /&gt;
        for (s in A,B)&lt;br /&gt;
        {&lt;br /&gt;
            for (n in range(MAX))&lt;br /&gt;
            {&lt;br /&gt;
                ok2run[s][n].signal();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    return punteggio;&lt;br /&gt;
}&lt;br /&gt;
p.e. pronto(s, n):&lt;br /&gt;
{&lt;br /&gt;
    if (partitafinita) return 1;&lt;br /&gt;
    if (!partita)&lt;br /&gt;
    {&lt;br /&gt;
        okpartita.wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti++;&lt;br /&gt;
    if (numpronti&amp;gt;=2*MAX)&lt;br /&gt;
    {&lt;br /&gt;
        ok2chiama.signal();&lt;br /&gt;
    }&lt;br /&gt;
    if (!(n in chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2run[s][n].wait();&lt;br /&gt;
    }&lt;br /&gt;
    numpronti--;&lt;br /&gt;
    return 0 if partita else 1;&lt;br /&gt;
}&lt;br /&gt;
allabandiera(s, n):&lt;br /&gt;
{&lt;br /&gt;
    contabandiera[s]++;&lt;br /&gt;
    if (winner == -1 &amp;amp;&amp;amp; contabandiera[s] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        winner = s;&lt;br /&gt;
    }&lt;br /&gt;
    if (contabandiera[A] == len(chiamati) &amp;amp;&amp;amp; contabandiera[B] == len(chiamati))&lt;br /&gt;
    {&lt;br /&gt;
        ok2punteggio.signal();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 16/07/2014 ==&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Monitor Bounded Buffer: (non richiesto dall'esercizio) */&lt;br /&gt;
queue q;&lt;br /&gt;
condition oktoread; // q.length() &amp;gt; 0&lt;br /&gt;
condition oktowrite; // q.length() &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry type read():&lt;br /&gt;
    if (q.length() == 0) oktoread.wait(); // controllo&lt;br /&gt;
    retval = q.dequeue(); // cambio lo stato&lt;br /&gt;
    // abilito coloro che possono essere abilitati dal cambiamento di stato&lt;br /&gt;
    oktowrite.signal() &lt;br /&gt;
    return retval;&lt;br /&gt;
&lt;br /&gt;
procedure entry void write(type elem):&lt;br /&gt;
    if (q.length() &amp;gt;= MAX) oktowrite.wait(); //controllo&lt;br /&gt;
    q.enqueue(elem); // cambio lo stato&lt;br /&gt;
    oktoread.signal(); // abilito chi può essere abilitato&lt;br /&gt;
&lt;br /&gt;
/* NOTE:&lt;br /&gt;
 * procedure entry ==&amp;gt; dichiarazione di funzioni (senza vedere l'implementazione &lt;br /&gt;
 * dall'esterno)&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/* Min-Max Monitor Bounded Buffer: */&lt;br /&gt;
&lt;br /&gt;
Queue Q;&lt;br /&gt;
&lt;br /&gt;
// Condition: OKTOREAD: Q.Length &amp;gt; MIN&lt;br /&gt;
// Condition: OKTOWRITE: Q.Length &amp;lt; MAX&lt;br /&gt;
&lt;br /&gt;
procedure entry: Type Read():&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;lt;= MIN) OKTOREAD.Wait(); // Controllo&lt;br /&gt;
    retval = Q.Dequeue(); // Cambio di stato&lt;br /&gt;
    OKTOWRITE.Signal(); // Abilito chi vuole scrivere&lt;br /&gt;
    return retval; // Qui sono sicuro perchè ne ho eliminato uno prima&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
procedure entry: void Write(Type elem):&lt;br /&gt;
{&lt;br /&gt;
    if (Q.Length &amp;gt;= MAX) OKTOWRITE.Wait() // Controllo&lt;br /&gt;
    Q.Enqueue(elem); // Cambio di stato&lt;br /&gt;
    if (Q.Length &amp;gt; MIN) OKTOREAD.Signal(); // Abilito chi vuole leggere&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
=== Esercizio c.2 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem&lt;br /&gt;
{&lt;br /&gt;
    Semaphore s;&lt;br /&gt;
    int counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct Elem V[]; // Vettore a dimensione variabile. I nuovi elementi sono initializzati a s = 0, counter = 0.&lt;br /&gt;
&lt;br /&gt;
void RendezVouz(int n)&lt;br /&gt;
{&lt;br /&gt;
    mutex.P(); // Blocco, decremento di 1 (il processo si blocca se il semaforo vale 0)&lt;br /&gt;
    V[n].counter++;&lt;br /&gt;
    if (V[n].counter &amp;lt; n)&lt;br /&gt;
    {&lt;br /&gt;
        mutex.V(); // Rilascia, incrementa di 1&lt;br /&gt;
        V[n].s.P();&lt;br /&gt;
    }&lt;br /&gt;
    V[n].counter--;&lt;br /&gt;
    if (V[n].counter &amp;gt; 0)&lt;br /&gt;
        V[n].s.V();&lt;br /&gt;
    else&lt;br /&gt;
        mutex.V();       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
    0241302 ==&amp;gt; soluzione corretta&lt;br /&gt;
(0)2   2200&lt;br /&gt;
(1)3   1111&lt;br /&gt;
(2)4   4442&lt;br /&gt;
(3)0   0333&lt;br /&gt;
&lt;br /&gt;
    2 3 4 0 1 2 3 4  0  1  2  3 ==&amp;gt; soluzione proposta, non corretta perchè non è la stringa più corta &lt;br /&gt;
2           1 1 1 1  0  0  0  0&lt;br /&gt;
3           3 2 2 2  2  1  1  1&lt;br /&gt;
4           4 4 3 3  3  3  2  2&lt;br /&gt;
0           0 0 0 4  4  4  4  3&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Mattiabiondi</name></author>
	</entry>
</feed>