<?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=Acsor</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=Acsor"/>
	<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php/Special:Contributions/Acsor"/>
	<updated>2026-04-29T20:22:40Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.35.5</generator>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Main_Page&amp;diff=2680</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Main_Page&amp;diff=2680"/>
		<updated>2021-05-03T20:29:36Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Aggiunto link alla pagina &amp;quot;Prove svolte e soluzioni proposte&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questo &amp;amp;egrave; il Wiki del Corso di [http://www.cs.unibo.it/~renzo/so Sistemi Operativi] della LT in Informatica dell'[https://www.unibo.it/it Università di Bologna].&lt;br /&gt;
&lt;br /&gt;
== ANNO ACCADEMICO 2020/21 ==&lt;br /&gt;
&lt;br /&gt;
=== Lezioni ===&lt;br /&gt;
Registro semestrale sulle attività svolte a lezione&lt;br /&gt;
&lt;br /&gt;
* [[Lezioni Anno Accademico 2020/21 I semestre]]&lt;br /&gt;
* [[Lezioni Anno Accademico 2020/21 II semestre]]&lt;br /&gt;
&lt;br /&gt;
=== Materiale didattico ===&lt;br /&gt;
* [[Documenti 2020/21]]&lt;br /&gt;
* [[Esempi, Esercizi ed Esperimenti 2020/21]]&lt;br /&gt;
* [[Decalogo di Programmazione Concorrente]]: suggerimenti e regole di massima sul come sviluppare correttamente codice concorrente&lt;br /&gt;
* [[Prove svolte e soluzioni proposte]]&lt;br /&gt;
* [[Glossario]]&lt;br /&gt;
&lt;br /&gt;
=== Annunci e servizi ===&lt;br /&gt;
# [[Lezioni ONLINE: limitiamo i danni del software proprietario]]&lt;br /&gt;
&lt;br /&gt;
== ANNI PRECEDENTI ==&lt;br /&gt;
* [[Materiale dell'AA 2019-20]]&lt;br /&gt;
* [[Materiale dell'AA 2018-19]]&lt;br /&gt;
* [[Materiale dell'AA 2017-18]]&lt;br /&gt;
* [[Materiale dell'AA 2016-17]]&lt;br /&gt;
* [[Materiale dell'AA 2015-16]]&lt;br /&gt;
* [[Materiale dell'AA 2014-15]]&lt;br /&gt;
* [[Materiale dell'AA 2013-14]]&lt;br /&gt;
&lt;br /&gt;
== ISCRIZIONE AL WIKI ==&lt;br /&gt;
Quando viene richiesto di risolvere un semplice calcolo artimetico per creare un account occorre ricordare quanto scritto [[qui]].&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=File:SistemiOperativi1920.pdf&amp;diff=2616</id>
		<title>File:SistemiOperativi1920.pdf</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=File:SistemiOperativi1920.pdf&amp;diff=2616"/>
		<updated>2020-09-13T16:20:23Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Acsor uploaded a new version of &amp;amp;quot;File:SistemiOperativi1920.pdf&amp;amp;quot;: Aggiornato alla versione del 13/09/2020.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Primo caricamento della conversione in PDF delle dispense del corso.&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2615</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2615"/>
		<updated>2020-09-13T15:28:26Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 24/09/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.09.24.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
La soluzione proposta fa uso della libreria [[Tool per semafori e monitor | pysm]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class VariableBoundedBuffer(monitor):&lt;br /&gt;
    def __init__(self, size):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._q = list()&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
        self._can_write, self._can_read = condition(self) for i in range(2)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def write(self, x):&lt;br /&gt;
        if self._max_elem &amp;lt;= len(self._q):&lt;br /&gt;
            self._can_write.wait()&lt;br /&gt;
&lt;br /&gt;
        self._q.append(x)&lt;br /&gt;
        self._can_read.signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def read(self):&lt;br /&gt;
        if not self._q:&lt;br /&gt;
            self._can_read.wait()&lt;br /&gt;
&lt;br /&gt;
        retval = self._q.pop(0)&lt;br /&gt;
&lt;br /&gt;
        if len(self._q) &amp;lt; self._max_elem:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
&lt;br /&gt;
        return retval&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def resize(self, size):&lt;br /&gt;
        if size &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Invalid size argument:&amp;quot;, size)&lt;br /&gt;
&lt;br /&gt;
        diff = size - self._max_elem&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
&lt;br /&gt;
        while diff &amp;gt; 0:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
            diff -= 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class process:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._stack = list()&lt;br /&gt;
&lt;br /&gt;
    def lsend(dest, m):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Any process is allowed to send itself messages in a LIFO order, except&lt;br /&gt;
        for the empty message `&amp;quot;&amp;quot;`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if (dest == self and m == &amp;quot;&amp;quot;):&lt;br /&gt;
            raise ValueError('Cannot self-send the empty message &amp;quot;&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
        self.asend(dest, m)&lt;br /&gt;
&lt;br /&gt;
    def lrecv():&lt;br /&gt;
        self.asend(self, &amp;quot;&amp;quot;)&lt;br /&gt;
        m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        # When we exit out of the loop, m.sender == self and m.text == &amp;quot;&amp;quot;&lt;br /&gt;
        while m.sender != self or m.text != &amp;quot;&amp;quot;:&lt;br /&gt;
            self._stack.append(m)&lt;br /&gt;
            m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        if not self._stack:&lt;br /&gt;
            return self.arecv(process.ANY)&lt;br /&gt;
        else:&lt;br /&gt;
            return self._stack.pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
                                                0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P1 |P1 |P1 |P1 |   |P2 |P2 |P2 |P2 |P1 |P1 |P1 |P1 |P2 |P2 |P1 |P2 |P2 |P3 |P3 |&lt;br /&gt;
IO    |   |   |   |   |P1 |P1 |   |   |   |P2 |P2 |   |   |P1 |P1 |   |   |   |P2 |P2 |&lt;br /&gt;
SPAWN |P1 |   |   |   |   |P2 |   |   |   |   |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P2 |P3 |P3 |   |   |P3 |P3 |P3 |P3 |   |   |P3 |   |   |   |   |   |   |   |   |&lt;br /&gt;
IO    |   |   |   |P3 |P3 |   |   |   |   |P3 |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
SPAWN |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
# No, non è richiesto. È sufficiente che il controller del dispositivo sia in grado di comunicare con la CPU sul bus e di segnalare il completamente di una delle sue operazioni al momento opportuno. (Il supporto DMA è utile se si vuole affidare la copiatura di grandi quantità di dati dalla memoria secondaria a quella primaria ai controller delle periferiche, e non alla CPU.)&lt;br /&gt;
# Un timer di sistema dotato di interrupt, in grado di notificare il sistema alle scadenze del quanto di tempo.&lt;br /&gt;
# Nessuno, infatti semplicità di realizzazione e basse richieste hardware compaiono tra i suoi principali vantaggi.&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato in data 11:30, 12 September 2020 (CEST) dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]). Ritengo sia: corretto (perché svolto in maniera pressappoco identica al mio)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor BoundedBuffer {&lt;br /&gt;
	queue&amp;lt;T&amp;gt; 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;
	condition oktoread, oktowrite;&lt;br /&gt;
&lt;br /&gt;
        BoundedBuffer () {&lt;br /&gt;
            q = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
            oktoread = new condition(this);&lt;br /&gt;
            oktowrite = new condition(this);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
	procedure entry T read() {&lt;br /&gt;
		if (q.length &amp;lt;= MIN) // Controllo&lt;br /&gt;
			oktoread.wait();&lt;br /&gt;
&lt;br /&gt;
		retval = q.dequeue(); // Cambio di stato&lt;br /&gt;
		oktowrite.signal(); // Abilito chi vuole scrivere&lt;br /&gt;
&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 (T elem) {&lt;br /&gt;
		if (q.length() &amp;gt;= MAX) // Controllo&lt;br /&gt;
			oktowrite.wait()&lt;br /&gt;
&lt;br /&gt;
		q.enqueue(elem); // Cambio di stato&lt;br /&gt;
&lt;br /&gt;
		if (q.length &amp;gt; MIN)&lt;br /&gt;
			oktoread.signal(); // Abilito chi vuole leggere&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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 Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
Questo svolgimento è basato sulla libreria ''pysm'' ricavabile da [[Tool per semafori e monitor]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from enum import auto, Enum&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
from random import randint&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Direction(Enum):&lt;br /&gt;
    UP = auto()&lt;br /&gt;
    DOWN = auto()&lt;br /&gt;
&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def from_int(cls, x):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `UP` if `x &amp;gt; 0`, `DOWN` if `x &amp;lt; 0` or raise an error otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if x &amp;gt; 0:&lt;br /&gt;
            return cls.UP&lt;br /&gt;
        elif x &amp;lt; 0:&lt;br /&gt;
            return cls.DOWN&lt;br /&gt;
        else:&lt;br /&gt;
            raise ValueError(&amp;quot;Unaccepted value 0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Elevator(monitor):&lt;br /&gt;
    def __init__(self, floors):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param floors: number of floors.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
&lt;br /&gt;
        # Total floors number and current floor, respectively&lt;br /&gt;
        self.floors, self._floor = floors, None&lt;br /&gt;
        # self._queue[f][dir] = condition queue associated with floor f and direction dir&lt;br /&gt;
        self._queue = {&lt;br /&gt;
            f: {d: condition(self) for d in Direction} for f in range(floors)&lt;br /&gt;
        }&lt;br /&gt;
        # self._exits[f] = k if k processes are to exit at floor f&lt;br /&gt;
        self._exits = {f: 0 for f in range(floors)}&lt;br /&gt;
        # Can the elevator close its door?&lt;br /&gt;
        self._can_close = condition(self)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def at_floor(self, floor, direction):&lt;br /&gt;
        self._floor = floor&lt;br /&gt;
        self._queue[floor][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        if self._exits[floor] &amp;gt; 0:&lt;br /&gt;
            self._can_close.wait()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def user_enter(self, _from, to):&lt;br /&gt;
        direction = Direction.from_int(to - _from)&lt;br /&gt;
&lt;br /&gt;
        self._queue[_from][direction].wait()&lt;br /&gt;
        self._queue[_from][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        self._exits[to] += 1&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def user_exit(self, _from, to):&lt;br /&gt;
        direction = Direction.from_int(to - _from)&lt;br /&gt;
&lt;br /&gt;
        if self._floor != to:&lt;br /&gt;
            self._queue[to][direction].wait()&lt;br /&gt;
            self._queue[to][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        self._exits[to] -= 1&lt;br /&gt;
&lt;br /&gt;
        if self._exits[to] == 0:&lt;br /&gt;
            self._can_close.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def elevator(e: Elevator):&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        for i in range(e.floors):&lt;br /&gt;
            print(&amp;quot;[%s] Going to floor %d&amp;quot; % (name, i))&lt;br /&gt;
            e.at_floor(i, Direction.UP)&lt;br /&gt;
&lt;br /&gt;
        for i in range(e.floors - 1, -1, -1):&lt;br /&gt;
            print(&amp;quot;[%s] Going to floor %d&amp;quot; % (name, i))&lt;br /&gt;
            e.at_floor(i, Direction.DOWN)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def user(e: Elevator):&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        _from, to = randint(0, e.floors - 1), randint(0, e.floors - 1)&lt;br /&gt;
&lt;br /&gt;
        if _from != to:&lt;br /&gt;
            print(&amp;quot;[%s] Entering from %d to %d&amp;quot; % (name, _from, to))&lt;br /&gt;
            e.user_enter(_from, to)&lt;br /&gt;
            print(&amp;quot;[%s] Exiting from %d to %d&amp;quot; % (name, _from, to))&lt;br /&gt;
            e.user_exit(_from, to)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    try:&lt;br /&gt;
        e = Elevator(6)&lt;br /&gt;
        threads = [&lt;br /&gt;
            threading.Thread(name='elevator', target=elevator, args=(e, )),&lt;br /&gt;
            threading.Thread(name='user0', target=user, args=(e, )),&lt;br /&gt;
            threading.Thread(name='user1', target=user, args=(e, )),&lt;br /&gt;
            threading.Thread(name='user2', target=user, args=(e, )),&lt;br /&gt;
            threading.Thread(name='user3', target=user, args=(e, )),&lt;br /&gt;
        ]&lt;br /&gt;
&lt;br /&gt;
        for t in threads:&lt;br /&gt;
            t.daemon = True&lt;br /&gt;
            t.start()&lt;br /&gt;
&lt;br /&gt;
        for t in threads:&lt;br /&gt;
            t.join()&lt;br /&gt;
    except KeyboardInterrupt:&lt;br /&gt;
        print(&amp;quot;Bye&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
* Stato: '''sbagliato'''. Non viene garantita la seguente proprietà, specificata dalla consegna: ''Quando l'ascensore arriva ad un piano non puo' ripartire se non sono scese tutte le persone che volevano giungere a quel piano''. Infatti se ci sono uno o più utenti in attesa di uscire ad un dato piano ''x'', allora atfloor(x, dir) sbloccherà un solo utente dalla sua chiamata a enter() senza che questi (e, assieme a lui, altri utenti in attesa di scendere) invochi exit(). [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:19, 12 September 2020 (CEST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// numero dei piani&lt;br /&gt;
#define N n&lt;br /&gt;
&lt;br /&gt;
monitor sabelev {&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;
        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;
        int direction = to &amp;gt; from ? 0: 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;
        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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2614</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2614"/>
		<updated>2020-09-13T15:25:27Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 24/09/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.09.24.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
La soluzione proposta fa uso della libreria [[Tool per semafori e monitor | pysm]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class VariableBoundedBuffer(monitor):&lt;br /&gt;
    def __init__(self, size):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._q = list()&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
        self._can_write, self._can_read = condition(self) for i in range(2)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def write(self, x):&lt;br /&gt;
        if self._max_elem &amp;lt;= len(self._q):&lt;br /&gt;
            self._can_write.wait()&lt;br /&gt;
&lt;br /&gt;
        self._q.append(x)&lt;br /&gt;
        self._can_read.signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def read(self):&lt;br /&gt;
        if not self._q:&lt;br /&gt;
            self._can_read.wait()&lt;br /&gt;
&lt;br /&gt;
        retval = self._q.pop(0)&lt;br /&gt;
&lt;br /&gt;
        if len(self._q) &amp;lt; self._max_elem:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
&lt;br /&gt;
        return retval&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def resize(self, size):&lt;br /&gt;
        if size &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Invalid size argument:&amp;quot;, size)&lt;br /&gt;
&lt;br /&gt;
        diff = size - self._max_elem&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
&lt;br /&gt;
        while diff &amp;gt; 0:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
            diff -= 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class process:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._stack = list()&lt;br /&gt;
&lt;br /&gt;
    def lsend(dest, m):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Any process is allowed to send itself messages in a LIFO order, except&lt;br /&gt;
        for the empty message `&amp;quot;&amp;quot;`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if (dest == self and m == &amp;quot;&amp;quot;):&lt;br /&gt;
            raise ValueError('Cannot self-send the empty message &amp;quot;&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
        self.asend(dest, m)&lt;br /&gt;
&lt;br /&gt;
    def lrecv():&lt;br /&gt;
        self.asend(self, &amp;quot;&amp;quot;)&lt;br /&gt;
        m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        # When we exit out of the loop, m.sender == self and m.text == &amp;quot;&amp;quot;&lt;br /&gt;
        while m.sender != self or m.text != &amp;quot;&amp;quot;:&lt;br /&gt;
            self._stack.append(m)&lt;br /&gt;
            m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        if not self._stack:&lt;br /&gt;
            return self.arecv(process.ANY)&lt;br /&gt;
        else:&lt;br /&gt;
            return self._stack.pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
                                                0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P1 |P1 |P1 |P1 |   |P2 |P2 |P2 |P2 |P1 |P1 |P1 |P1 |P2 |P2 |P1 |P2 |P2 |P3 |P3 |&lt;br /&gt;
IO    |   |   |   |   |P1 |P1 |   |   |   |P2 |P2 |   |   |P1 |P1 |   |   |   |P2 |P2 |&lt;br /&gt;
SPAWN |P1 |   |   |   |   |P2 |   |   |   |   |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P2 |P3 |P3 |   |   |P3 |P3 |P3 |P3 |   |   |P3 |   |   |   |   |   |   |   |   |&lt;br /&gt;
IO    |   |   |   |P3 |P3 |   |   |   |   |P3 |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
SPAWN |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
# No, non è richiesto. È sufficiente che il controller del dispositivo sia in grado di comunicare con la CPU sul bus e di segnalare il completamente di una delle sue operazioni al momento opportuno. (Il supporto DMA è utile se si vuole affidare la copiatura di grandi quantità di dati dalla memoria secondaria a quella primaria ai controller delle periferiche, e non alla CPU.)&lt;br /&gt;
# Un timer di sistema dotato di interrupt, in grado di notificare il sistema alle scadenze del quanto di tempo.&lt;br /&gt;
# Nessuno, infatti semplicità di realizzazione e basse richieste hardware compaiono tra i suoi principali vantaggi.&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato in data 11:30, 12 September 2020 (CEST) dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]). Ritengo sia: corretto (perché svolto in maniera pressappoco identica al mio)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor BoundedBuffer {&lt;br /&gt;
	queue&amp;lt;T&amp;gt; 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;
	condition oktoread, oktowrite;&lt;br /&gt;
&lt;br /&gt;
        BoundedBuffer () {&lt;br /&gt;
            q = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
            oktoread = new condition(this);&lt;br /&gt;
            oktowrite = new condition(this);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
	procedure entry T read() {&lt;br /&gt;
		if (q.length &amp;lt;= MIN) // Controllo&lt;br /&gt;
			oktoread.wait();&lt;br /&gt;
&lt;br /&gt;
		retval = q.dequeue(); // Cambio di stato&lt;br /&gt;
		oktowrite.signal(); // Abilito chi vuole scrivere&lt;br /&gt;
&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 (T elem) {&lt;br /&gt;
		if (q.length() &amp;gt;= MAX) // Controllo&lt;br /&gt;
			oktowrite.wait()&lt;br /&gt;
&lt;br /&gt;
		q.enqueue(elem); // Cambio di stato&lt;br /&gt;
&lt;br /&gt;
		if (q.length &amp;gt; MIN)&lt;br /&gt;
			oktoread.signal(); // Abilito chi vuole leggere&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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 Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
Questo svolgimento è basato sulla libreria ''pysm'' ricavabile da [[Tool per semafori e monitor]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from enum import auto, Enum&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
from random import randint&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Direction(Enum):&lt;br /&gt;
    UP = auto()&lt;br /&gt;
    DOWN = auto()&lt;br /&gt;
&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def from_int(cls, x):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `UP` if `x &amp;gt; 0`, `DOWN` if `x &amp;lt; 0` or raise an error otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if x &amp;gt; 0:&lt;br /&gt;
            return cls.UP&lt;br /&gt;
        elif x &amp;lt; 0:&lt;br /&gt;
            return cls.DOWN&lt;br /&gt;
        else:&lt;br /&gt;
            raise ValueError(&amp;quot;Unaccepted value 0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Elevator(monitor):&lt;br /&gt;
    def __init__(self, floors):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param floors: number of floors.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
&lt;br /&gt;
        self.floors, self._floor = floors, None&lt;br /&gt;
        # self._queue[f][dir] = condition queue associated with floor f and direction dir&lt;br /&gt;
        self._queue = {&lt;br /&gt;
            f: {d: condition(self) for d in Direction} for f in range(floors)&lt;br /&gt;
        }&lt;br /&gt;
        self._exits = {f: 0 for f in range(floors)}&lt;br /&gt;
        self._can_close = condition(self)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def at_floor(self, floor, direction):&lt;br /&gt;
        self._floor = floor&lt;br /&gt;
        self._queue[floor][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        if self._exits[floor] &amp;gt; 0:&lt;br /&gt;
            self._can_close.wait()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def user_enter(self, _from, to):&lt;br /&gt;
        direction = Direction.from_int(to - _from)&lt;br /&gt;
&lt;br /&gt;
        self._queue[_from][direction].wait()&lt;br /&gt;
        self._queue[_from][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        self._exits[to] += 1&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def user_exit(self, _from, to):&lt;br /&gt;
        direction = Direction.from_int(to - _from)&lt;br /&gt;
&lt;br /&gt;
        if self._floor != to:&lt;br /&gt;
            self._queue[to][direction].wait()&lt;br /&gt;
            self._queue[to][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        self._exits[to] -= 1&lt;br /&gt;
&lt;br /&gt;
        if self._exits[to] == 0:&lt;br /&gt;
            self._can_close.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def elevator(e: Elevator):&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        for i in range(e.floors):&lt;br /&gt;
            print(&amp;quot;[%s] Going to floor %d&amp;quot; % (name, i))&lt;br /&gt;
            e.at_floor(i, Direction.UP)&lt;br /&gt;
&lt;br /&gt;
        for i in range(e.floors - 1, -1, -1):&lt;br /&gt;
            print(&amp;quot;[%s] Going to floor %d&amp;quot; % (name, i))&lt;br /&gt;
            e.at_floor(i, Direction.DOWN)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def user(e: Elevator):&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        _from, to = randint(0, e.floors - 1), randint(0, e.floors - 1)&lt;br /&gt;
&lt;br /&gt;
        if _from != to:&lt;br /&gt;
            print(&amp;quot;[%s] Entering from %d to %d&amp;quot; % (name, _from, to))&lt;br /&gt;
            e.user_enter(_from, to)&lt;br /&gt;
            print(&amp;quot;[%s] Exiting from %d to %d&amp;quot; % (name, _from, to))&lt;br /&gt;
            e.user_exit(_from, to)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    try:&lt;br /&gt;
        e = Elevator(6)&lt;br /&gt;
        threads = [&lt;br /&gt;
            threading.Thread(name='elevator', target=elevator, args=(e, )),&lt;br /&gt;
            threading.Thread(name='user0', target=user, args=(e, )),&lt;br /&gt;
            threading.Thread(name='user1', target=user, args=(e, )),&lt;br /&gt;
            threading.Thread(name='user2', target=user, args=(e, )),&lt;br /&gt;
            threading.Thread(name='user3', target=user, args=(e, )),&lt;br /&gt;
        ]&lt;br /&gt;
&lt;br /&gt;
        for t in threads:&lt;br /&gt;
            t.daemon = True&lt;br /&gt;
            t.start()&lt;br /&gt;
&lt;br /&gt;
        for t in threads:&lt;br /&gt;
            t.join()&lt;br /&gt;
    except KeyboardInterrupt:&lt;br /&gt;
        print(&amp;quot;Bye&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
* Stato: '''sbagliato'''. Non viene garantita la seguente proprietà, specificata dalla consegna: ''Quando l'ascensore arriva ad un piano non puo' ripartire se non sono scese tutte le persone che volevano giungere a quel piano''. Infatti se ci sono uno o più utenti in attesa di uscire ad un dato piano ''x'', allora atfloor(x, dir) sbloccherà un solo utente dalla sua chiamata a enter() senza che questi (e, assieme a lui, altri utenti in attesa di scendere) invochi exit(). [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:19, 12 September 2020 (CEST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// numero dei piani&lt;br /&gt;
#define N n&lt;br /&gt;
&lt;br /&gt;
monitor sabelev {&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;
        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;
        int direction = to &amp;gt; from ? 0: 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;
        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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2613</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2613"/>
		<updated>2020-09-13T13:07:48Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 24/09/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.09.24.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
La soluzione proposta fa uso della libreria [[Tool per semafori e monitor | pysm]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class VariableBoundedBuffer(monitor):&lt;br /&gt;
    def __init__(self, size):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._q = list()&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
        self._can_write, self._can_read = condition(self) for i in range(2)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def write(self, x):&lt;br /&gt;
        if self._max_elem &amp;lt;= len(self._q):&lt;br /&gt;
            self._can_write.wait()&lt;br /&gt;
&lt;br /&gt;
        self._q.append(x)&lt;br /&gt;
        self._can_read.signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def read(self):&lt;br /&gt;
        if not self._q:&lt;br /&gt;
            self._can_read.wait()&lt;br /&gt;
&lt;br /&gt;
        retval = self._q.pop(0)&lt;br /&gt;
&lt;br /&gt;
        if len(self._q) &amp;lt; self._max_elem:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
&lt;br /&gt;
        return retval&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def resize(self, size):&lt;br /&gt;
        if size &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Invalid size argument:&amp;quot;, size)&lt;br /&gt;
&lt;br /&gt;
        diff = size - self._max_elem&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
&lt;br /&gt;
        while diff &amp;gt; 0:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
            diff -= 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class process:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._stack = list()&lt;br /&gt;
&lt;br /&gt;
    def lsend(dest, m):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Any process is allowed to send itself messages in a LIFO order, except&lt;br /&gt;
        for the empty message `&amp;quot;&amp;quot;`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if (dest == self and m == &amp;quot;&amp;quot;):&lt;br /&gt;
            raise ValueError('Cannot self-send the empty message &amp;quot;&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
        self.asend(dest, m)&lt;br /&gt;
&lt;br /&gt;
    def lrecv():&lt;br /&gt;
        self.asend(self, &amp;quot;&amp;quot;)&lt;br /&gt;
        m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        # When we exit out of the loop, m.sender == self and m.text == &amp;quot;&amp;quot;&lt;br /&gt;
        while m.sender != self or m.text != &amp;quot;&amp;quot;:&lt;br /&gt;
            self._stack.append(m)&lt;br /&gt;
            m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        if not self._stack:&lt;br /&gt;
            return self.arecv(process.ANY)&lt;br /&gt;
        else:&lt;br /&gt;
            return self._stack.pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
                                                0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P1 |P1 |P1 |P1 |   |P2 |P2 |P2 |P2 |P1 |P1 |P1 |P1 |P2 |P2 |P1 |P2 |P2 |P3 |P3 |&lt;br /&gt;
IO    |   |   |   |   |P1 |P1 |   |   |   |P2 |P2 |   |   |P1 |P1 |   |   |   |P2 |P2 |&lt;br /&gt;
SPAWN |P1 |   |   |   |   |P2 |   |   |   |   |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P2 |P3 |P3 |   |   |P3 |P3 |P3 |P3 |   |   |P3 |   |   |   |   |   |   |   |   |&lt;br /&gt;
IO    |   |   |   |P3 |P3 |   |   |   |   |P3 |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
SPAWN |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
# No, non è richiesto. È sufficiente che il controller del dispositivo sia in grado di comunicare con la CPU sul bus e di segnalare il completamente di una delle sue operazioni al momento opportuno. (Il supporto DMA è utile se si vuole affidare la copiatura di grandi quantità di dati dalla memoria secondaria a quella primaria ai controller delle periferiche, e non alla CPU.)&lt;br /&gt;
# Un timer di sistema dotato di interrupt, in grado di notificare il sistema alle scadenze del quanto di tempo.&lt;br /&gt;
# Nessuno, infatti semplicità di realizzazione e basse richieste hardware compaiono tra i suoi principali vantaggi.&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato in data 11:30, 12 September 2020 (CEST) dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]). Ritengo sia: corretto (perché svolto in maniera pressappoco identica al mio)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor BoundedBuffer {&lt;br /&gt;
	queue&amp;lt;T&amp;gt; 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;
	condition oktoread, oktowrite;&lt;br /&gt;
&lt;br /&gt;
        BoundedBuffer () {&lt;br /&gt;
            q = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
            oktoread = new condition(this);&lt;br /&gt;
            oktowrite = new condition(this);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
	procedure entry T read() {&lt;br /&gt;
		if (q.length &amp;lt;= MIN) // Controllo&lt;br /&gt;
			oktoread.wait();&lt;br /&gt;
&lt;br /&gt;
		retval = q.dequeue(); // Cambio di stato&lt;br /&gt;
		oktowrite.signal(); // Abilito chi vuole scrivere&lt;br /&gt;
&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 (T elem) {&lt;br /&gt;
		if (q.length() &amp;gt;= MAX) // Controllo&lt;br /&gt;
			oktowrite.wait()&lt;br /&gt;
&lt;br /&gt;
		q.enqueue(elem); // Cambio di stato&lt;br /&gt;
&lt;br /&gt;
		if (q.length &amp;gt; MIN)&lt;br /&gt;
			oktoread.signal(); // Abilito chi vuole leggere&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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 Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
Questo svolgimento è basato sulla libreria ''pysm'' ricavabile da [[Tool per semafori e monitor]].&lt;br /&gt;
&lt;br /&gt;
* Stato: '''sbagliato/in fase di correzione'''. I processi utente possono liberamente invocare exit() senza che l'ascensore sia giunto al piano desiderato. [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 15:07, 13 September 2020 (CEST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from enum import auto, Enum&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Direction(Enum):&lt;br /&gt;
    UP = auto()&lt;br /&gt;
    DOWN = auto()&lt;br /&gt;
&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def from_int(cls, x):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `UP` if `x &amp;gt; 0`, `DOWN` if `x &amp;lt; 0` or raise an error otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if x &amp;gt; 0:&lt;br /&gt;
            return cls.UP&lt;br /&gt;
        elif x &amp;lt; 0:&lt;br /&gt;
            return cls.DOWN&lt;br /&gt;
        else:&lt;br /&gt;
            raise ValueError(&amp;quot;Unaccepted value 0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Elevator(monitor):&lt;br /&gt;
    def __init__(self, floors):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param floors: number of floors.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        # self._queue[f][dir] = condition queue associated with floor f and direction dir&lt;br /&gt;
        self._queue = {&lt;br /&gt;
            f: {d: condition(self) for d in Direction} for f in range(floors)&lt;br /&gt;
        }&lt;br /&gt;
        # self._exits[k] = v if v users are waiting to get off at floor k&lt;br /&gt;
        self._exits = {f: 0 for f in range(floors)}&lt;br /&gt;
        # Is the elevator allowed to close its door?&lt;br /&gt;
        self._can_close = condition(self)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def at_floor(self, floor, direction):&lt;br /&gt;
        self._queue[floor][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        while self._exits[floor] &amp;gt; 0:&lt;br /&gt;
            self._can_close.wait()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def enter(self, _from, to):&lt;br /&gt;
        direction = Direction.from_int(to - _from)&lt;br /&gt;
&lt;br /&gt;
        self._queue[_from][direction].wait()&lt;br /&gt;
        self._queue[_from][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        self._exits[to] += 1&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def exit(self, _from, to):&lt;br /&gt;
        self._exits[to] -= 1&lt;br /&gt;
        self._can_close.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
* Stato: '''sbagliato'''. Non viene garantita la seguente proprietà, specificata dalla consegna: ''Quando l'ascensore arriva ad un piano non puo' ripartire se non sono scese tutte le persone che volevano giungere a quel piano''. Infatti se ci sono uno o più utenti in attesa di uscire ad un dato piano ''x'', allora atfloor(x, dir) sbloccherà un solo utente dalla sua chiamata a enter() senza che questi (e, assieme a lui, altri utenti in attesa di scendere) invochi exit(). [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:19, 12 September 2020 (CEST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// numero dei piani&lt;br /&gt;
#define N n&lt;br /&gt;
&lt;br /&gt;
monitor sabelev {&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;
        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;
        int direction = to &amp;gt; from ? 0: 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;
        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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2612</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2612"/>
		<updated>2020-09-13T09:00:10Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 24/09/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.09.24.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
La soluzione proposta fa uso della libreria [[Tool per semafori e monitor | pysm]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class VariableBoundedBuffer(monitor):&lt;br /&gt;
    def __init__(self, size):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._q = list()&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
        self._can_write, self._can_read = condition(self) for i in range(2)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def write(self, x):&lt;br /&gt;
        if self._max_elem &amp;lt;= len(self._q):&lt;br /&gt;
            self._can_write.wait()&lt;br /&gt;
&lt;br /&gt;
        self._q.append(x)&lt;br /&gt;
        self._can_read.signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def read(self):&lt;br /&gt;
        if not self._q:&lt;br /&gt;
            self._can_read.wait()&lt;br /&gt;
&lt;br /&gt;
        retval = self._q.pop(0)&lt;br /&gt;
&lt;br /&gt;
        if len(self._q) &amp;lt; self._max_elem:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
&lt;br /&gt;
        return retval&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def resize(self, size):&lt;br /&gt;
        if size &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Invalid size argument:&amp;quot;, size)&lt;br /&gt;
&lt;br /&gt;
        diff = size - self._max_elem&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
&lt;br /&gt;
        while diff &amp;gt; 0:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
            diff -= 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class process:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._stack = list()&lt;br /&gt;
&lt;br /&gt;
    def lsend(dest, m):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Any process is allowed to send itself messages in a LIFO order, except&lt;br /&gt;
        for the empty message `&amp;quot;&amp;quot;`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if (dest == self and m == &amp;quot;&amp;quot;):&lt;br /&gt;
            raise ValueError('Cannot self-send the empty message &amp;quot;&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
        self.asend(dest, m)&lt;br /&gt;
&lt;br /&gt;
    def lrecv():&lt;br /&gt;
        self.asend(self, &amp;quot;&amp;quot;)&lt;br /&gt;
        m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        # When we exit out of the loop, m.sender == self and m.text == &amp;quot;&amp;quot;&lt;br /&gt;
        while m.sender != self or m.text != &amp;quot;&amp;quot;:&lt;br /&gt;
            self._stack.append(m)&lt;br /&gt;
            m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        if not self._stack:&lt;br /&gt;
            return self.arecv(process.ANY)&lt;br /&gt;
        else:&lt;br /&gt;
            return self._stack.pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
                                                0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P1 |P1 |P1 |P1 |   |P2 |P2 |P2 |P2 |P1 |P1 |P1 |P1 |P2 |P2 |P1 |P2 |P2 |P3 |P3 |&lt;br /&gt;
IO    |   |   |   |   |P1 |P1 |   |   |   |P2 |P2 |   |   |P1 |P1 |   |   |   |P2 |P2 |&lt;br /&gt;
SPAWN |P1 |   |   |   |   |P2 |   |   |   |   |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P2 |P3 |P3 |   |   |P3 |P3 |P3 |P3 |   |   |P3 |   |   |   |   |   |   |   |   |&lt;br /&gt;
IO    |   |   |   |P3 |P3 |   |   |   |   |P3 |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
SPAWN |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
# No, non è richiesto. È sufficiente che il controller del dispositivo sia in grado di comunicare con la CPU sul bus e di segnalare il completamente di una delle sue operazioni al momento opportuno. (Il supporto DMA è utile se si vuole affidare la copiatura di grandi quantità di dati dalla memoria secondaria a quella primaria ai controller delle periferiche, e non alla CPU.)&lt;br /&gt;
# Un timer di sistema dotato di interrupt, in grado di notificare il sistema alle scadenze del quanto di tempo.&lt;br /&gt;
# Nessuno, infatti semplicità di realizzazione e basse richieste hardware compaiono tra i suoi principali vantaggi.&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato in data 11:30, 12 September 2020 (CEST) dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]). Ritengo sia: corretto (perché svolto in maniera pressappoco identica al mio)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor BoundedBuffer {&lt;br /&gt;
	queue&amp;lt;T&amp;gt; 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;
	condition oktoread, oktowrite;&lt;br /&gt;
&lt;br /&gt;
        BoundedBuffer () {&lt;br /&gt;
            q = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
            oktoread = new condition(this);&lt;br /&gt;
            oktowrite = new condition(this);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
	procedure entry T read() {&lt;br /&gt;
		if (q.length &amp;lt;= MIN) // Controllo&lt;br /&gt;
			oktoread.wait();&lt;br /&gt;
&lt;br /&gt;
		retval = q.dequeue(); // Cambio di stato&lt;br /&gt;
		oktowrite.signal(); // Abilito chi vuole scrivere&lt;br /&gt;
&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 (T elem) {&lt;br /&gt;
		if (q.length() &amp;gt;= MAX) // Controllo&lt;br /&gt;
			oktowrite.wait()&lt;br /&gt;
&lt;br /&gt;
		q.enqueue(elem); // Cambio di stato&lt;br /&gt;
&lt;br /&gt;
		if (q.length &amp;gt; MIN)&lt;br /&gt;
			oktoread.signal(); // Abilito chi vuole leggere&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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 Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
Questo svolgimento è basato sulla libreria ''pysm'' ricavabile da [[Tool per semafori e monitor]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from enum import auto, Enum&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Direction(Enum):&lt;br /&gt;
    UP = auto()&lt;br /&gt;
    DOWN = auto()&lt;br /&gt;
&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def from_int(cls, x):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `UP` if `x &amp;gt; 0`, `DOWN` if `x &amp;lt; 0` or raise an error otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if x &amp;gt; 0:&lt;br /&gt;
            return cls.UP&lt;br /&gt;
        elif x &amp;lt; 0:&lt;br /&gt;
            return cls.DOWN&lt;br /&gt;
        else:&lt;br /&gt;
            raise ValueError(&amp;quot;Unaccepted value 0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Elevator(monitor):&lt;br /&gt;
    def __init__(self, floors):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param floors: number of floors.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        # self._queue[f][dir] = condition queue associated with floor f and direction dir&lt;br /&gt;
        self._queue = {&lt;br /&gt;
            f: {d: condition(self) for d in Direction} for f in range(floors)&lt;br /&gt;
        }&lt;br /&gt;
        # self._exits[k] = v if v users are waiting to get off at floor k&lt;br /&gt;
        self._exits = {f: 0 for f in range(floors)}&lt;br /&gt;
        # Is the elevator allowed to close its door?&lt;br /&gt;
        self._can_close = condition(self)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def at_floor(self, floor, direction):&lt;br /&gt;
        self._queue[floor][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        while self._exits[floor] &amp;gt; 0:&lt;br /&gt;
            self._can_close.wait()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def enter(self, _from, to):&lt;br /&gt;
        direction = Direction.from_int(to - _from)&lt;br /&gt;
&lt;br /&gt;
        self._queue[_from][direction].wait()&lt;br /&gt;
        self._queue[_from][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        self._exits[to] += 1&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def exit(self, _from, to):&lt;br /&gt;
        self._exits[to] -= 1&lt;br /&gt;
        self._can_close.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
* Stato: '''sbagliato'''. Non viene garantita la seguente proprietà, specificata dalla consegna: ''Quando l'ascensore arriva ad un piano non puo' ripartire se non sono scese tutte le persone che volevano giungere a quel piano''. Infatti se ci sono uno o più utenti in attesa di uscire ad un dato piano ''x'', allora atfloor(x, dir) sbloccherà un solo utente dalla sua chiamata a enter() senza che questi (e, assieme a lui, altri utenti in attesa di scendere) invochi exit(). [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:19, 12 September 2020 (CEST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// numero dei piani&lt;br /&gt;
#define N n&lt;br /&gt;
&lt;br /&gt;
monitor sabelev {&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;
        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;
        int direction = to &amp;gt; from ? 0: 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;
        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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2611</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2611"/>
		<updated>2020-09-13T08:59:48Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Ri-svolto es. c.1 esame 03/06/2014&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 24/09/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.09.24.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
La soluzione proposta fa uso della libreria [[Tool per semafori e monitor | pysm]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class VariableBoundedBuffer(monitor):&lt;br /&gt;
    def __init__(self, size):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._q = list()&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
        self._can_write, self._can_read = condition(self) for i in range(2)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def write(self, x):&lt;br /&gt;
        if self._max_elem &amp;lt;= len(self._q):&lt;br /&gt;
            self._can_write.wait()&lt;br /&gt;
&lt;br /&gt;
        self._q.append(x)&lt;br /&gt;
        self._can_read.signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def read(self):&lt;br /&gt;
        if not self._q:&lt;br /&gt;
            self._can_read.wait()&lt;br /&gt;
&lt;br /&gt;
        retval = self._q.pop(0)&lt;br /&gt;
&lt;br /&gt;
        if len(self._q) &amp;lt; self._max_elem:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
&lt;br /&gt;
        return retval&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def resize(self, size):&lt;br /&gt;
        if size &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Invalid size argument:&amp;quot;, size)&lt;br /&gt;
&lt;br /&gt;
        diff = size - self._max_elem&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
&lt;br /&gt;
        # Poiché non è possibile trovare le due code d'attesa contemporaneamente&lt;br /&gt;
        # non vuote e poiché non è possibile ricevere nuove richieste nel&lt;br /&gt;
        # frattempo, ciclare su una signal() è sicuro&lt;br /&gt;
        while diff &amp;gt; 0:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
            diff -= 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class process:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._stack = list()&lt;br /&gt;
&lt;br /&gt;
    def lsend(dest, m):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Any process is allowed to send itself messages in a LIFO order, except&lt;br /&gt;
        for the empty message `&amp;quot;&amp;quot;`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if (dest == self and m == &amp;quot;&amp;quot;):&lt;br /&gt;
            raise ValueError('Cannot self-send the empty message &amp;quot;&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
        self.asend(dest, m)&lt;br /&gt;
&lt;br /&gt;
    def lrecv():&lt;br /&gt;
        self.asend(self, &amp;quot;&amp;quot;)&lt;br /&gt;
        m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        # When we exit out of the loop, m.sender == self and m.text == &amp;quot;&amp;quot;&lt;br /&gt;
        while m.sender != self or m.text != &amp;quot;&amp;quot;:&lt;br /&gt;
            self._stack.append(m)&lt;br /&gt;
            m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        if not self._stack:&lt;br /&gt;
            return self.arecv(process.ANY)&lt;br /&gt;
        else:&lt;br /&gt;
            return self._stack.pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
                                                0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P1 |P1 |P1 |P1 |   |P2 |P2 |P2 |P2 |P1 |P1 |P1 |P1 |P2 |P2 |P1 |P2 |P2 |P3 |P3 |&lt;br /&gt;
IO    |   |   |   |   |P1 |P1 |   |   |   |P2 |P2 |   |   |P1 |P1 |   |   |   |P2 |P2 |&lt;br /&gt;
SPAWN |P1 |   |   |   |   |P2 |   |   |   |   |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P2 |P3 |P3 |   |   |P3 |P3 |P3 |P3 |   |   |P3 |   |   |   |   |   |   |   |   |&lt;br /&gt;
IO    |   |   |   |P3 |P3 |   |   |   |   |P3 |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
SPAWN |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
# No, non è richiesto. È sufficiente che il controller del dispositivo sia in grado di comunicare con la CPU sul bus e di segnalare il completamente di una delle sue operazioni al momento opportuno. (Il supporto DMA è utile se si vuole affidare la copiatura di grandi quantità di dati dalla memoria secondaria a quella primaria ai controller delle periferiche, e non alla CPU.)&lt;br /&gt;
# Un timer di sistema dotato di interrupt, in grado di notificare il sistema alle scadenze del quanto di tempo.&lt;br /&gt;
# Nessuno, infatti semplicità di realizzazione e basse richieste hardware compaiono tra i suoi principali vantaggi.&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato in data 11:30, 12 September 2020 (CEST) dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]). Ritengo sia: corretto (perché svolto in maniera pressappoco identica al mio)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor BoundedBuffer {&lt;br /&gt;
	queue&amp;lt;T&amp;gt; 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;
	condition oktoread, oktowrite;&lt;br /&gt;
&lt;br /&gt;
        BoundedBuffer () {&lt;br /&gt;
            q = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
            oktoread = new condition(this);&lt;br /&gt;
            oktowrite = new condition(this);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
	procedure entry T read() {&lt;br /&gt;
		if (q.length &amp;lt;= MIN) // Controllo&lt;br /&gt;
			oktoread.wait();&lt;br /&gt;
&lt;br /&gt;
		retval = q.dequeue(); // Cambio di stato&lt;br /&gt;
		oktowrite.signal(); // Abilito chi vuole scrivere&lt;br /&gt;
&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 (T elem) {&lt;br /&gt;
		if (q.length() &amp;gt;= MAX) // Controllo&lt;br /&gt;
			oktowrite.wait()&lt;br /&gt;
&lt;br /&gt;
		q.enqueue(elem); // Cambio di stato&lt;br /&gt;
&lt;br /&gt;
		if (q.length &amp;gt; MIN)&lt;br /&gt;
			oktoread.signal(); // Abilito chi vuole leggere&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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 Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
Questo svolgimento è basato sulla libreria ''pysm'' ricavabile da [[Tool per semafori e monitor]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from enum import auto, Enum&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Direction(Enum):&lt;br /&gt;
    UP = auto()&lt;br /&gt;
    DOWN = auto()&lt;br /&gt;
&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def from_int(cls, x):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `UP` if `x &amp;gt; 0`, `DOWN` if `x &amp;lt; 0` or raise an error otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if x &amp;gt; 0:&lt;br /&gt;
            return cls.UP&lt;br /&gt;
        elif x &amp;lt; 0:&lt;br /&gt;
            return cls.DOWN&lt;br /&gt;
        else:&lt;br /&gt;
            raise ValueError(&amp;quot;Unaccepted value 0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Elevator(monitor):&lt;br /&gt;
    def __init__(self, floors):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param floors: number of floors.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        # self._queue[f][dir] = condition queue associated with floor f and direction dir&lt;br /&gt;
        self._queue = {&lt;br /&gt;
            f: {d: condition(self) for d in Direction} for f in range(floors)&lt;br /&gt;
        }&lt;br /&gt;
        # self._exits[k] = v if v users are waiting to get off at floor k&lt;br /&gt;
        self._exits = {f: 0 for f in range(floors)}&lt;br /&gt;
        # Is the elevator allowed to close its door?&lt;br /&gt;
        self._can_close = condition(self)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def at_floor(self, floor, direction):&lt;br /&gt;
        self._queue[floor][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        while self._exits[floor] &amp;gt; 0:&lt;br /&gt;
            self._can_close.wait()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def enter(self, _from, to):&lt;br /&gt;
        direction = Direction.from_int(to - _from)&lt;br /&gt;
&lt;br /&gt;
        self._queue[_from][direction].wait()&lt;br /&gt;
        self._queue[_from][direction].signal()&lt;br /&gt;
&lt;br /&gt;
        self._exits[to] += 1&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def exit(self, _from, to):&lt;br /&gt;
        self._exits[to] -= 1&lt;br /&gt;
        self._can_close.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
* Stato: '''sbagliato'''. Non viene garantita la seguente proprietà, specificata dalla consegna: ''Quando l'ascensore arriva ad un piano non puo' ripartire se non sono scese tutte le persone che volevano giungere a quel piano''. Infatti se ci sono uno o più utenti in attesa di uscire ad un dato piano ''x'', allora atfloor(x, dir) sbloccherà un solo utente dalla sua chiamata a enter() senza che questi (e, assieme a lui, altri utenti in attesa di scendere) invochi exit(). [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:19, 12 September 2020 (CEST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// numero dei piani&lt;br /&gt;
#define N n&lt;br /&gt;
&lt;br /&gt;
monitor sabelev {&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;
        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;
        int direction = to &amp;gt; from ? 0: 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;
        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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2610</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2610"/>
		<updated>2020-09-12T15:48:40Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 24/09/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.09.24.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
La soluzione proposta fa uso della libreria [[Tool per semafori e monitor | pysm]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class VariableBoundedBuffer(monitor):&lt;br /&gt;
    def __init__(self, size):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._q = list()&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
        self._can_write, self._can_read = condition(self) for i in range(2)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def write(self, x):&lt;br /&gt;
        if self._max_elem &amp;lt;= len(self._q):&lt;br /&gt;
            self._can_write.wait()&lt;br /&gt;
&lt;br /&gt;
        self._q.append(x)&lt;br /&gt;
        self._can_read.signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def read(self):&lt;br /&gt;
        if not self._q:&lt;br /&gt;
            self._can_read.wait()&lt;br /&gt;
&lt;br /&gt;
        retval = self._q.pop(0)&lt;br /&gt;
&lt;br /&gt;
        if len(self._q) &amp;lt; self._max_elem:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
&lt;br /&gt;
        return retval&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def resize(self, size):&lt;br /&gt;
        if size &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Invalid size argument:&amp;quot;, size)&lt;br /&gt;
&lt;br /&gt;
        diff = size - self._max_elem&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
&lt;br /&gt;
        # Poiché non è possibile trovare le due code d'attesa contemporaneamente&lt;br /&gt;
        # non vuote e poiché non è possibile ricevere nuove richieste nel&lt;br /&gt;
        # frattempo, ciclare su una signal() è sicuro&lt;br /&gt;
        while diff &amp;gt; 0:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
            diff -= 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class process:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._stack = list()&lt;br /&gt;
&lt;br /&gt;
    def lsend(dest, m):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Any process is allowed to send itself messages in a LIFO order, except&lt;br /&gt;
        for the empty message `&amp;quot;&amp;quot;`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if (dest == self and m == &amp;quot;&amp;quot;):&lt;br /&gt;
            raise ValueError('Cannot self-send the empty message &amp;quot;&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
        self.asend(dest, m)&lt;br /&gt;
&lt;br /&gt;
    def lrecv():&lt;br /&gt;
        self.asend(self, &amp;quot;&amp;quot;)&lt;br /&gt;
        m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        # When we exit out of the loop, m.sender == self and m.text == &amp;quot;&amp;quot;&lt;br /&gt;
        while m.sender != self or m.text != &amp;quot;&amp;quot;:&lt;br /&gt;
            self._stack.append(m)&lt;br /&gt;
            m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        if not self._stack:&lt;br /&gt;
            return self.arecv(process.ANY)&lt;br /&gt;
        else:&lt;br /&gt;
            return self._stack.pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
                                                0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P1 |P1 |P1 |P1 |   |P2 |P2 |P2 |P2 |P1 |P1 |P1 |P1 |P2 |P2 |P1 |P2 |P2 |P3 |P3 |&lt;br /&gt;
IO    |   |   |   |   |P1 |P1 |   |   |   |P2 |P2 |   |   |P1 |P1 |   |   |   |P2 |P2 |&lt;br /&gt;
SPAWN |P1 |   |   |   |   |P2 |   |   |   |   |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P2 |P3 |P3 |   |   |P3 |P3 |P3 |P3 |   |   |P3 |   |   |   |   |   |   |   |   |&lt;br /&gt;
IO    |   |   |   |P3 |P3 |   |   |   |   |P3 |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
SPAWN |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
# No, non è richiesto. È sufficiente che il controller del dispositivo sia in grado di comunicare con la CPU sul bus e di segnalare il completamente di una delle sue operazioni al momento opportuno. (Il supporto DMA è utile se si vuole affidare la copiatura di grandi quantità di dati dalla memoria secondaria a quella primaria ai controller delle periferiche, e non alla CPU.)&lt;br /&gt;
# Un timer di sistema dotato di interrupt, in grado di notificare il sistema alle scadenze del quanto di tempo.&lt;br /&gt;
# Nessuno, infatti semplicità di realizzazione e basse richieste hardware compaiono tra i suoi principali vantaggi.&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato in data 11:30, 12 September 2020 (CEST) dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]). Ritengo sia: corretto (perché svolto in maniera pressappoco identica al mio)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor BoundedBuffer {&lt;br /&gt;
	queue&amp;lt;T&amp;gt; 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;
	condition oktoread, oktowrite;&lt;br /&gt;
&lt;br /&gt;
        BoundedBuffer () {&lt;br /&gt;
            q = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
            oktoread = new condition(this);&lt;br /&gt;
            oktowrite = new condition(this);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
	procedure entry T read() {&lt;br /&gt;
		if (q.length &amp;lt;= MIN) // Controllo&lt;br /&gt;
			oktoread.wait();&lt;br /&gt;
&lt;br /&gt;
		retval = q.dequeue(); // Cambio di stato&lt;br /&gt;
		oktowrite.signal(); // Abilito chi vuole scrivere&lt;br /&gt;
&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 (T elem) {&lt;br /&gt;
		if (q.length() &amp;gt;= MAX) // Controllo&lt;br /&gt;
			oktowrite.wait()&lt;br /&gt;
&lt;br /&gt;
		q.enqueue(elem); // Cambio di stato&lt;br /&gt;
&lt;br /&gt;
		if (q.length &amp;gt; MIN)&lt;br /&gt;
			oktoread.signal(); // Abilito chi vuole leggere&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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 Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
Questo svolgimento è basato sulla libreria ''pysm'' ricavabile da [[Tool per semafori e monitor]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from enum import auto, Enum&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Direction(Enum):&lt;br /&gt;
    UP = auto()&lt;br /&gt;
    DOWN = auto()&lt;br /&gt;
&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def from_int(cls, x):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `UP` if `x &amp;gt; 0`, `DOWN` if `x &amp;lt; 0` or raise an error otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if x &amp;gt; 0:&lt;br /&gt;
            return cls.UP&lt;br /&gt;
        elif x &amp;lt; 0:&lt;br /&gt;
            return cls.DOWN&lt;br /&gt;
        else:&lt;br /&gt;
            raise ValueError(&amp;quot;Unaccepted value 0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Elevator(monitor):&lt;br /&gt;
    def __init__(self, floors):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param floors: number of floors.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self._floor_queue = {i: condition(self) for i in range(floors)}&lt;br /&gt;
        self._just_entered = {i: 0 for i in range(floors)}&lt;br /&gt;
&lt;br /&gt;
        self._my_dir = {i: condition(self) for i in Direction}&lt;br /&gt;
&lt;br /&gt;
        # Can the elevator close its door?&lt;br /&gt;
        self._can_close = condition(self)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def at_floor(self, floor, direction):&lt;br /&gt;
        self._my_dir[direction].signal()&lt;br /&gt;
        self._floor_queue[floor].signal()&lt;br /&gt;
&lt;br /&gt;
        while self._just_entered[floor] &amp;gt; 0:&lt;br /&gt;
            self._can_close.wait()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def enter(self, _from, to):&lt;br /&gt;
        direction = Direction.from_int(to - _from)&lt;br /&gt;
&lt;br /&gt;
        self._my_dir[direction].wait()&lt;br /&gt;
        self._my_dir[direction].signal()&lt;br /&gt;
&lt;br /&gt;
        self._floor_queue[_from].wait()&lt;br /&gt;
        self._floor_queue[_from].signal()&lt;br /&gt;
        self._just_entered[_from] += 1&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def exit(self, _from, to):&lt;br /&gt;
        self._just_entered[_from] -= 1&lt;br /&gt;
        self._can_close.signal()&lt;br /&gt;
&lt;br /&gt;
        self._floor_queue[to].wait()&lt;br /&gt;
        self._floor_queue[to].signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
* Stato: '''sbagliato'''. Non viene garantita la seguente proprietà, specificata dalla consegna: ''Quando l'ascensore arriva ad un piano non puo' ripartire se non sono scese tutte le persone che volevano giungere a quel piano''. Infatti se ci sono uno o più utenti in attesa di uscire ad un dato piano ''x'', allora atfloor(x, dir) sbloccherà un solo utente dalla sua chiamata a enter() senza che questi (e, assieme a lui, altri utenti in attesa di scendere) invochi exit(). [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:19, 12 September 2020 (CEST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// numero dei piani&lt;br /&gt;
#define N n&lt;br /&gt;
&lt;br /&gt;
monitor sabelev {&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;
        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;
        int direction = to &amp;gt; from ? 0: 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;
        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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2609</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2609"/>
		<updated>2020-09-12T15:43:59Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Svolto es. c.1 esame 03/06/2014&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 24/09/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.09.24.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
La soluzione proposta fa uso della libreria [[Tool per semafori e monitor | pysm]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class VariableBoundedBuffer(monitor):&lt;br /&gt;
    def __init__(self, size):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._q = list()&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
        self._can_write, self._can_read = condition(self) for i in range(2)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def write(self, x):&lt;br /&gt;
        if self._max_elem &amp;lt;= len(self._q):&lt;br /&gt;
            self._can_write.wait()&lt;br /&gt;
&lt;br /&gt;
        self._q.append(x)&lt;br /&gt;
        self._can_read.signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def read(self):&lt;br /&gt;
        if not self._q:&lt;br /&gt;
            self._can_read.wait()&lt;br /&gt;
&lt;br /&gt;
        retval = self._q.pop(0)&lt;br /&gt;
&lt;br /&gt;
        if len(self._q) &amp;lt; self._max_elem:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
&lt;br /&gt;
        return retval&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def resize(self, size):&lt;br /&gt;
        if size &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Invalid size argument:&amp;quot;, size)&lt;br /&gt;
&lt;br /&gt;
        diff = size - self._max_elem&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
&lt;br /&gt;
        # Poiché non è possibile trovare le due code d'attesa contemporaneamente&lt;br /&gt;
        # non vuote e poiché non è possibile ricevere nuove richieste nel&lt;br /&gt;
        # frattempo, ciclare su una signal() è sicuro&lt;br /&gt;
        while diff &amp;gt; 0:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
            diff -= 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class process:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._stack = list()&lt;br /&gt;
&lt;br /&gt;
    def lsend(dest, m):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Any process is allowed to send itself messages in a LIFO order, except&lt;br /&gt;
        for the empty message `&amp;quot;&amp;quot;`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if (dest == self and m == &amp;quot;&amp;quot;):&lt;br /&gt;
            raise ValueError('Cannot self-send the empty message &amp;quot;&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
        self.asend(dest, m)&lt;br /&gt;
&lt;br /&gt;
    def lrecv():&lt;br /&gt;
        self.asend(self, &amp;quot;&amp;quot;)&lt;br /&gt;
        m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        # When we exit out of the loop, m.sender == self and m.text == &amp;quot;&amp;quot;&lt;br /&gt;
        while m.sender != self or m.text != &amp;quot;&amp;quot;:&lt;br /&gt;
            self._stack.append(m)&lt;br /&gt;
            m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        if not self._stack:&lt;br /&gt;
            return self.arecv(process.ANY)&lt;br /&gt;
        else:&lt;br /&gt;
            return self._stack.pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
                                                0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P1 |P1 |P1 |P1 |   |P2 |P2 |P2 |P2 |P1 |P1 |P1 |P1 |P2 |P2 |P1 |P2 |P2 |P3 |P3 |&lt;br /&gt;
IO    |   |   |   |   |P1 |P1 |   |   |   |P2 |P2 |   |   |P1 |P1 |   |   |   |P2 |P2 |&lt;br /&gt;
SPAWN |P1 |   |   |   |   |P2 |   |   |   |   |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P2 |P3 |P3 |   |   |P3 |P3 |P3 |P3 |   |   |P3 |   |   |   |   |   |   |   |   |&lt;br /&gt;
IO    |   |   |   |P3 |P3 |   |   |   |   |P3 |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
SPAWN |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
# No, non è richiesto. È sufficiente che il controller del dispositivo sia in grado di comunicare con la CPU sul bus e di segnalare il completamente di una delle sue operazioni al momento opportuno. (Il supporto DMA è utile se si vuole affidare la copiatura di grandi quantità di dati dalla memoria secondaria a quella primaria ai controller delle periferiche, e non alla CPU.)&lt;br /&gt;
# Un timer di sistema dotato di interrupt, in grado di notificare il sistema alle scadenze del quanto di tempo.&lt;br /&gt;
# Nessuno, infatti semplicità di realizzazione e basse richieste hardware compaiono tra i suoi principali vantaggi.&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato in data 11:30, 12 September 2020 (CEST) dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]). Ritengo sia: corretto (perché svolto in maniera pressappoco identica al mio)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor BoundedBuffer {&lt;br /&gt;
	queue&amp;lt;T&amp;gt; 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;
	condition oktoread, oktowrite;&lt;br /&gt;
&lt;br /&gt;
        BoundedBuffer () {&lt;br /&gt;
            q = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
            oktoread = new condition(this);&lt;br /&gt;
            oktowrite = new condition(this);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
	procedure entry T read() {&lt;br /&gt;
		if (q.length &amp;lt;= MIN) // Controllo&lt;br /&gt;
			oktoread.wait();&lt;br /&gt;
&lt;br /&gt;
		retval = q.dequeue(); // Cambio di stato&lt;br /&gt;
		oktowrite.signal(); // Abilito chi vuole scrivere&lt;br /&gt;
&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 (T elem) {&lt;br /&gt;
		if (q.length() &amp;gt;= MAX) // Controllo&lt;br /&gt;
			oktowrite.wait()&lt;br /&gt;
&lt;br /&gt;
		q.enqueue(elem); // Cambio di stato&lt;br /&gt;
&lt;br /&gt;
		if (q.length &amp;gt; MIN)&lt;br /&gt;
			oktoread.signal(); // Abilito chi vuole leggere&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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 Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
Questo svolgimento è basato sulla libreria ''pysm'' ricavabile da [[Tool per semafori e monitor]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from enum import auto, Enum&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Direction(Enum):&lt;br /&gt;
    UP = auto()&lt;br /&gt;
    DOWN = auto()&lt;br /&gt;
&lt;br /&gt;
    @classmethod&lt;br /&gt;
    def from_int(cls, x):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `UP` if `x &amp;gt; 0`, `DOWN` if `x &amp;lt; 0` or raise an error otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if x &amp;gt; 0:&lt;br /&gt;
            return cls.UP&lt;br /&gt;
        elif x &amp;lt; 0:&lt;br /&gt;
            return cls.DOWN&lt;br /&gt;
        else:&lt;br /&gt;
            raise ValueError(&amp;quot;Unaccepted value 0&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class Elevator(monitor):&lt;br /&gt;
    def __init__(self, floors):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param floors: number of floors.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self._floor_queue = {i: condition(self) for i in range(floors)}&lt;br /&gt;
        self._just_entered = {i: 0 for i in range(floors)}&lt;br /&gt;
&lt;br /&gt;
        self._direction = None&lt;br /&gt;
        self._my_dir = {i: condition(self) for i in Direction}&lt;br /&gt;
&lt;br /&gt;
        # Can the elevator close its door?&lt;br /&gt;
        self._can_close = condition(self)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def at_floor(self, floor, direction):&lt;br /&gt;
        self._direction = direction&lt;br /&gt;
        self._my_dir[direction].signal()&lt;br /&gt;
&lt;br /&gt;
        self._floor_queue[floor].signal()&lt;br /&gt;
&lt;br /&gt;
        while self._just_entered[floor] &amp;gt; 0:&lt;br /&gt;
            self._can_close.wait()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def enter(self, _from, to):&lt;br /&gt;
        direction = Direction.from_int(to - _from)&lt;br /&gt;
&lt;br /&gt;
        if direction != self._direction:&lt;br /&gt;
            self._my_dir[direction].wait()&lt;br /&gt;
            self._my_dir[direction].signal()&lt;br /&gt;
&lt;br /&gt;
        self._floor_queue[_from].wait()&lt;br /&gt;
        self._floor_queue[_from].signal()&lt;br /&gt;
        self._just_entered[_from] += 1&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def exit(self, _from, to):&lt;br /&gt;
        self._just_entered[_from] -= 1&lt;br /&gt;
        self._can_close.signal()&lt;br /&gt;
&lt;br /&gt;
        self._floor_queue[to].wait()&lt;br /&gt;
        self._floor_queue[to].signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
* Stato: '''sbagliato'''. Non viene garantita la seguente proprietà, specificata dalla consegna: ''Quando l'ascensore arriva ad un piano non puo' ripartire se non sono scese tutte le persone che volevano giungere a quel piano''. Infatti se ci sono uno o più utenti in attesa di uscire ad un dato piano ''x'', allora atfloor(x, dir) sbloccherà un solo utente dalla sua chiamata a enter() senza che questi (e, assieme a lui, altri utenti in attesa di scendere) invochi exit(). [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:19, 12 September 2020 (CEST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// numero dei piani&lt;br /&gt;
#define N n&lt;br /&gt;
&lt;br /&gt;
monitor sabelev {&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;
        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;
        int direction = to &amp;gt; from ? 0: 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;
        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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2608</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2608"/>
		<updated>2020-09-12T15:19:34Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Segnato es c.1 esame 03/06/2014 come sbagliato&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 24/09/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.09.24.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
La soluzione proposta fa uso della libreria [[Tool per semafori e monitor | pysm]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class VariableBoundedBuffer(monitor):&lt;br /&gt;
    def __init__(self, size):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._q = list()&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
        self._can_write, self._can_read = condition(self) for i in range(2)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def write(self, x):&lt;br /&gt;
        if self._max_elem &amp;lt;= len(self._q):&lt;br /&gt;
            self._can_write.wait()&lt;br /&gt;
&lt;br /&gt;
        self._q.append(x)&lt;br /&gt;
        self._can_read.signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def read(self):&lt;br /&gt;
        if not self._q:&lt;br /&gt;
            self._can_read.wait()&lt;br /&gt;
&lt;br /&gt;
        retval = self._q.pop(0)&lt;br /&gt;
&lt;br /&gt;
        if len(self._q) &amp;lt; self._max_elem:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
&lt;br /&gt;
        return retval&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def resize(self, size):&lt;br /&gt;
        if size &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Invalid size argument:&amp;quot;, size)&lt;br /&gt;
&lt;br /&gt;
        diff = size - self._max_elem&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
&lt;br /&gt;
        # Poiché non è possibile trovare le due code d'attesa contemporaneamente&lt;br /&gt;
        # non vuote e poiché non è possibile ricevere nuove richieste nel&lt;br /&gt;
        # frattempo, ciclare su una signal() è sicuro&lt;br /&gt;
        while diff &amp;gt; 0:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
            diff -= 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class process:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._stack = list()&lt;br /&gt;
&lt;br /&gt;
    def lsend(dest, m):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Any process is allowed to send itself messages in a LIFO order, except&lt;br /&gt;
        for the empty message `&amp;quot;&amp;quot;`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if (dest == self and m == &amp;quot;&amp;quot;):&lt;br /&gt;
            raise ValueError('Cannot self-send the empty message &amp;quot;&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
        self.asend(dest, m)&lt;br /&gt;
&lt;br /&gt;
    def lrecv():&lt;br /&gt;
        self.asend(self, &amp;quot;&amp;quot;)&lt;br /&gt;
        m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        # When we exit out of the loop, m.sender == self and m.text == &amp;quot;&amp;quot;&lt;br /&gt;
        while m.sender != self or m.text != &amp;quot;&amp;quot;:&lt;br /&gt;
            self._stack.append(m)&lt;br /&gt;
            m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        if not self._stack:&lt;br /&gt;
            return self.arecv(process.ANY)&lt;br /&gt;
        else:&lt;br /&gt;
            return self._stack.pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
                                                0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P1 |P1 |P1 |P1 |   |P2 |P2 |P2 |P2 |P1 |P1 |P1 |P1 |P2 |P2 |P1 |P2 |P2 |P3 |P3 |&lt;br /&gt;
IO    |   |   |   |   |P1 |P1 |   |   |   |P2 |P2 |   |   |P1 |P1 |   |   |   |P2 |P2 |&lt;br /&gt;
SPAWN |P1 |   |   |   |   |P2 |   |   |   |   |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P2 |P3 |P3 |   |   |P3 |P3 |P3 |P3 |   |   |P3 |   |   |   |   |   |   |   |   |&lt;br /&gt;
IO    |   |   |   |P3 |P3 |   |   |   |   |P3 |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
SPAWN |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
# No, non è richiesto. È sufficiente che il controller del dispositivo sia in grado di comunicare con la CPU sul bus e di segnalare il completamente di una delle sue operazioni al momento opportuno. (Il supporto DMA è utile se si vuole affidare la copiatura di grandi quantità di dati dalla memoria secondaria a quella primaria ai controller delle periferiche, e non alla CPU.)&lt;br /&gt;
# Un timer di sistema dotato di interrupt, in grado di notificare il sistema alle scadenze del quanto di tempo.&lt;br /&gt;
# Nessuno, infatti semplicità di realizzazione e basse richieste hardware compaiono tra i suoi principali vantaggi.&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato in data 11:30, 12 September 2020 (CEST) dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]). Ritengo sia: corretto (perché svolto in maniera pressappoco identica al mio)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor BoundedBuffer {&lt;br /&gt;
	queue&amp;lt;T&amp;gt; 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;
	condition oktoread, oktowrite;&lt;br /&gt;
&lt;br /&gt;
        BoundedBuffer () {&lt;br /&gt;
            q = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
            oktoread = new condition(this);&lt;br /&gt;
            oktowrite = new condition(this);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
	procedure entry T read() {&lt;br /&gt;
		if (q.length &amp;lt;= MIN) // Controllo&lt;br /&gt;
			oktoread.wait();&lt;br /&gt;
&lt;br /&gt;
		retval = q.dequeue(); // Cambio di stato&lt;br /&gt;
		oktowrite.signal(); // Abilito chi vuole scrivere&lt;br /&gt;
&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 (T elem) {&lt;br /&gt;
		if (q.length() &amp;gt;= MAX) // Controllo&lt;br /&gt;
			oktowrite.wait()&lt;br /&gt;
&lt;br /&gt;
		q.enqueue(elem); // Cambio di stato&lt;br /&gt;
&lt;br /&gt;
		if (q.length &amp;gt; MIN)&lt;br /&gt;
			oktoread.signal(); // Abilito chi vuole leggere&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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;
&lt;br /&gt;
=== Esercizio c.1 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
* Stato: '''sbagliato'''. Non viene garantita la seguente proprietà, specificata dalla consegna: ''Quando l'ascensore arriva ad un piano non puo' ripartire se non sono scese tutte le persone che volevano giungere a quel piano''. Infatti se ci sono uno o più utenti in attesa di uscire ad un dato piano ''x'', allora atfloor(x, dir) sbloccherà un solo utente dalla sua chiamata a enter() senza che questi (e, assieme a lui, altri utenti in attesa di scendere) invochi exit(). [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:19, 12 September 2020 (CEST)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// numero dei piani&lt;br /&gt;
#define N n&lt;br /&gt;
&lt;br /&gt;
monitor sabelev {&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;
        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;
        int direction = to &amp;gt; from ? 0: 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;
        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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2607</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2607"/>
		<updated>2020-09-12T09:31:39Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 24/09/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.09.24.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
La soluzione proposta fa uso della libreria [[Tool per semafori e monitor | pysm]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class VariableBoundedBuffer(monitor):&lt;br /&gt;
    def __init__(self, size):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._q = list()&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
        self._can_write, self._can_read = condition(self) for i in range(2)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def write(self, x):&lt;br /&gt;
        if self._max_elem &amp;lt;= len(self._q):&lt;br /&gt;
            self._can_write.wait()&lt;br /&gt;
&lt;br /&gt;
        self._q.append(x)&lt;br /&gt;
        self._can_read.signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def read(self):&lt;br /&gt;
        if not self._q:&lt;br /&gt;
            self._can_read.wait()&lt;br /&gt;
&lt;br /&gt;
        retval = self._q.pop(0)&lt;br /&gt;
&lt;br /&gt;
        if len(self._q) &amp;lt; self._max_elem:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
&lt;br /&gt;
        return retval&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def resize(self, size):&lt;br /&gt;
        if size &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Invalid size argument:&amp;quot;, size)&lt;br /&gt;
&lt;br /&gt;
        diff = size - self._max_elem&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
&lt;br /&gt;
        # Poiché non è possibile trovare le due code d'attesa contemporaneamente&lt;br /&gt;
        # non vuote e poiché non è possibile ricevere nuove richieste nel&lt;br /&gt;
        # frattempo, ciclare su una signal() è sicuro&lt;br /&gt;
        while diff &amp;gt; 0:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
            diff -= 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class process:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._stack = list()&lt;br /&gt;
&lt;br /&gt;
    def lsend(dest, m):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Any process is allowed to send itself messages in a LIFO order, except&lt;br /&gt;
        for the empty message `&amp;quot;&amp;quot;`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if (dest == self and m == &amp;quot;&amp;quot;):&lt;br /&gt;
            raise ValueError('Cannot self-send the empty message &amp;quot;&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
        self.asend(dest, m)&lt;br /&gt;
&lt;br /&gt;
    def lrecv():&lt;br /&gt;
        self.asend(self, &amp;quot;&amp;quot;)&lt;br /&gt;
        m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        # When we exit out of the loop, m.sender == self and m.text == &amp;quot;&amp;quot;&lt;br /&gt;
        while m.sender != self or m.text != &amp;quot;&amp;quot;:&lt;br /&gt;
            self._stack.append(m)&lt;br /&gt;
            m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        if not self._stack:&lt;br /&gt;
            return self.arecv(process.ANY)&lt;br /&gt;
        else:&lt;br /&gt;
            return self._stack.pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
                                                0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P1 |P1 |P1 |P1 |   |P2 |P2 |P2 |P2 |P1 |P1 |P1 |P1 |P2 |P2 |P1 |P2 |P2 |P3 |P3 |&lt;br /&gt;
IO    |   |   |   |   |P1 |P1 |   |   |   |P2 |P2 |   |   |P1 |P1 |   |   |   |P2 |P2 |&lt;br /&gt;
SPAWN |P1 |   |   |   |   |P2 |   |   |   |   |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P2 |P3 |P3 |   |   |P3 |P3 |P3 |P3 |   |   |P3 |   |   |   |   |   |   |   |   |&lt;br /&gt;
IO    |   |   |   |P3 |P3 |   |   |   |   |P3 |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
SPAWN |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
# No, non è richiesto. È sufficiente che il controller del dispositivo sia in grado di comunicare con la CPU sul bus e di segnalare il completamente di una delle sue operazioni al momento opportuno. (Il supporto DMA è utile se si vuole affidare la copiatura di grandi quantità di dati dalla memoria secondaria a quella primaria ai controller delle periferiche, e non alla CPU.)&lt;br /&gt;
# Un timer di sistema dotato di interrupt, in grado di notificare il sistema alle scadenze del quanto di tempo.&lt;br /&gt;
# Nessuno, infatti semplicità di realizzazione e basse richieste hardware compaiono tra i suoi principali vantaggi.&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato in data 11:30, 12 September 2020 (CEST) dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]). Ritengo sia: corretto (perché svolto in maniera pressappoco identica al mio)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor BoundedBuffer {&lt;br /&gt;
	queue&amp;lt;T&amp;gt; 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;
	condition oktoread, oktowrite;&lt;br /&gt;
&lt;br /&gt;
        BoundedBuffer () {&lt;br /&gt;
            q = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
            oktoread = new condition(this);&lt;br /&gt;
            oktowrite = new condition(this);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
	procedure entry T read() {&lt;br /&gt;
		if (q.length &amp;lt;= MIN) // Controllo&lt;br /&gt;
			oktoread.wait();&lt;br /&gt;
&lt;br /&gt;
		retval = q.dequeue(); // Cambio di stato&lt;br /&gt;
		oktowrite.signal(); // Abilito chi vuole scrivere&lt;br /&gt;
&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 (T elem) {&lt;br /&gt;
		if (q.length() &amp;gt;= MAX) // Controllo&lt;br /&gt;
			oktowrite.wait()&lt;br /&gt;
&lt;br /&gt;
		q.enqueue(elem); // Cambio di stato&lt;br /&gt;
&lt;br /&gt;
		if (q.length &amp;gt; MIN)&lt;br /&gt;
			oktoread.signal(); // Abilito chi vuole leggere&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2606</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2606"/>
		<updated>2020-09-12T09:30:14Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Controllato es c.1 esame 16/07/2014&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 24/09/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.09.24.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
La soluzione proposta fa uso della libreria [[Tool per semafori e monitor | pysm]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class VariableBoundedBuffer(monitor):&lt;br /&gt;
    def __init__(self, size):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._q = list()&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
        self._can_write, self._can_read = condition(self) for i in range(2)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def write(self, x):&lt;br /&gt;
        if self._max_elem &amp;lt;= len(self._q):&lt;br /&gt;
            self._can_write.wait()&lt;br /&gt;
&lt;br /&gt;
        self._q.append(x)&lt;br /&gt;
        self._can_read.signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def read(self):&lt;br /&gt;
        if not self._q:&lt;br /&gt;
            self._can_read.wait()&lt;br /&gt;
&lt;br /&gt;
        retval = self._q.pop(0)&lt;br /&gt;
&lt;br /&gt;
        if len(self._q) &amp;lt; self._max_elem:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
&lt;br /&gt;
        return retval&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def resize(self, size):&lt;br /&gt;
        if size &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Invalid size argument:&amp;quot;, size)&lt;br /&gt;
&lt;br /&gt;
        diff = size - self._max_elem&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
&lt;br /&gt;
        # Poiché non è possibile trovare le due code d'attesa contemporaneamente&lt;br /&gt;
        # non vuote e poiché non è possibile ricevere nuove richieste nel&lt;br /&gt;
        # frattempo, ciclare su una signal() è sicuro&lt;br /&gt;
        while diff &amp;gt; 0:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
            diff -= 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class process:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._stack = list()&lt;br /&gt;
&lt;br /&gt;
    def lsend(dest, m):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Any process is allowed to send itself messages in a LIFO order, except&lt;br /&gt;
        for the empty message `&amp;quot;&amp;quot;`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if (dest == self and m == &amp;quot;&amp;quot;):&lt;br /&gt;
            raise ValueError('Cannot self-send the empty message &amp;quot;&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
        self.asend(dest, m)&lt;br /&gt;
&lt;br /&gt;
    def lrecv():&lt;br /&gt;
        self.asend(self, &amp;quot;&amp;quot;)&lt;br /&gt;
        m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        # When we exit out of the loop, m.sender == self and m.text == &amp;quot;&amp;quot;&lt;br /&gt;
        while m.sender != self or m.text != &amp;quot;&amp;quot;:&lt;br /&gt;
            self._stack.append(m)&lt;br /&gt;
            m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        if not self._stack:&lt;br /&gt;
            return self.arecv(process.ANY)&lt;br /&gt;
        else:&lt;br /&gt;
            return self._stack.pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
                                                0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P1 |P1 |P1 |P1 |   |P2 |P2 |P2 |P2 |P1 |P1 |P1 |P1 |P2 |P2 |P1 |P2 |P2 |P3 |P3 |&lt;br /&gt;
IO    |   |   |   |   |P1 |P1 |   |   |   |P2 |P2 |   |   |P1 |P1 |   |   |   |P2 |P2 |&lt;br /&gt;
SPAWN |P1 |   |   |   |   |P2 |   |   |   |   |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P2 |P3 |P3 |   |   |P3 |P3 |P3 |P3 |   |   |P3 |   |   |   |   |   |   |   |   |&lt;br /&gt;
IO    |   |   |   |P3 |P3 |   |   |   |   |P3 |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
SPAWN |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
# No, non è richiesto. È sufficiente che il controller del dispositivo sia in grado di comunicare con la CPU sul bus e di segnalare il completamente di una delle sue operazioni al momento opportuno. (Il supporto DMA è utile se si vuole affidare la copiatura di grandi quantità di dati dalla memoria secondaria a quella primaria ai controller delle periferiche, e non alla CPU.)&lt;br /&gt;
# Un timer di sistema dotato di interrupt, in grado di notificare il sistema alle scadenze del quanto di tempo.&lt;br /&gt;
# Nessuno, infatti semplicità di realizzazione e basse richieste hardware compaiono tra i suoi principali vantaggi.&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato in data 11:30, 12 September 2020 (CEST) dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]). Ritengo sia: corretto (perché fatto in maniera pressappoco identica)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor BoundedBuffer {&lt;br /&gt;
	queue&amp;lt;T&amp;gt; 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;
	condition oktoread, oktowrite;&lt;br /&gt;
&lt;br /&gt;
        BoundedBuffer () {&lt;br /&gt;
            q = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
            oktoread = new condition(this);&lt;br /&gt;
            oktowrite = new condition(this);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
	procedure entry T read() {&lt;br /&gt;
		if (q.length &amp;lt;= MIN) // Controllo&lt;br /&gt;
			oktoread.wait();&lt;br /&gt;
&lt;br /&gt;
		retval = q.dequeue(); // Cambio di stato&lt;br /&gt;
		oktowrite.signal(); // Abilito chi vuole scrivere&lt;br /&gt;
&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 (T elem) {&lt;br /&gt;
		if (q.length() &amp;gt;= MAX) // Controllo&lt;br /&gt;
			oktowrite.wait()&lt;br /&gt;
&lt;br /&gt;
		q.enqueue(elem); // Cambio di stato&lt;br /&gt;
&lt;br /&gt;
		if (q.length &amp;gt; MIN)&lt;br /&gt;
			oktoread.signal(); // Abilito chi vuole leggere&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2605</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=2605"/>
		<updated>2020-09-10T18:31:49Z</updated>

		<summary type="html">&lt;p&gt;Acsor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina raccoglie prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review. Chiunque prenda visione di un esercizio è pregato (per il bene collettivo) a lasciare una [https://www.mediawiki.org/wiki/Help:Signatures propria firma] con nome utente e data di visualizzazione indicando se lo svolgimento è ritenuto corretto; in caso di svolgimento scorretto è invece invitato ad apportare una correzione o a '''spiegare il perché dell'errore commesso''', lasciando come nel caso precedente il proprio nome utente e data di correzione.&lt;br /&gt;
&lt;br /&gt;
Al fine di verificare la correttezza degli esercizi di concorrenza, segnaliamo la presenza di [[Tool_per_semafori_e_monitor|strumenti di programmazione concorrente]] per i linguaggi C e Python.&lt;br /&gt;
&lt;br /&gt;
== Prove scritte ==&lt;br /&gt;
* [[Prove scritte 2019]]&lt;br /&gt;
* [[Prove scritte 2018]]&lt;br /&gt;
* [[Prove scritte 2017]]&lt;br /&gt;
* [[Prove scritte 2015]]&lt;br /&gt;
* [[Prove scritte 2014]]&lt;br /&gt;
* [[Prove scritte 2011]]&lt;br /&gt;
* [[Prove scritte 2005]]&lt;br /&gt;
&lt;br /&gt;
== Prove pratiche ==&lt;br /&gt;
* [[Prove pratiche 2018]]&lt;br /&gt;
* [[Prove pratiche 2016]]&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2604</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2604"/>
		<updated>2020-09-10T18:14:52Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Svolto esame del 24/09/2014 (da controllare)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 24/09/2014 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2014.09.24.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
La soluzione proposta fa uso della libreria [[Tool per semafori e monitor | pysm]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
from pysm import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class VariableBoundedBuffer(monitor):&lt;br /&gt;
    def __init__(self, size):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._q = list()&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
        self._can_write, self._can_read = condition(self) for i in range(2)&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def write(self, x):&lt;br /&gt;
        if self._max_elem &amp;lt;= len(self._q):&lt;br /&gt;
            self._can_write.wait()&lt;br /&gt;
&lt;br /&gt;
        self._q.append(x)&lt;br /&gt;
        self._can_read.signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def read(self):&lt;br /&gt;
        if not self._q:&lt;br /&gt;
            self._can_read.wait()&lt;br /&gt;
&lt;br /&gt;
        retval = self._q.pop(0)&lt;br /&gt;
&lt;br /&gt;
        if len(self._q) &amp;lt; self._max_elem:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
&lt;br /&gt;
        return retval&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def resize(self, size):&lt;br /&gt;
        if size &amp;lt; 0:&lt;br /&gt;
            raise ValueError(&amp;quot;Invalid size argument:&amp;quot;, size)&lt;br /&gt;
&lt;br /&gt;
        diff = size - self._max_elem&lt;br /&gt;
        self._max_elem = size&lt;br /&gt;
&lt;br /&gt;
        # Poiché non è possibile trovare le due code d'attesa contemporaneamente&lt;br /&gt;
        # non vuote e poiché non è possibile ricevere nuove richieste nel&lt;br /&gt;
        # frattempo, ciclare su una signal() è sicuro&lt;br /&gt;
        while diff &amp;gt; 0:&lt;br /&gt;
            self._can_write.signal()&lt;br /&gt;
            diff -= 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class process:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self._stack = list()&lt;br /&gt;
&lt;br /&gt;
    def lsend(dest, m):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Any process is allowed to send itself messages in a LIFO order, except&lt;br /&gt;
        for the empty message `&amp;quot;&amp;quot;`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        if (dest == self and m == &amp;quot;&amp;quot;):&lt;br /&gt;
            raise ValueError('Cannot self-send the empty message &amp;quot;&amp;quot;')&lt;br /&gt;
&lt;br /&gt;
        self.asend(dest, m)&lt;br /&gt;
&lt;br /&gt;
    def lrecv():&lt;br /&gt;
        self.asend(self, &amp;quot;&amp;quot;)&lt;br /&gt;
        m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        # When we exit out of the loop, m.sender == self and m.text == &amp;quot;&amp;quot;&lt;br /&gt;
        while m.sender != self or m.text != &amp;quot;&amp;quot;:&lt;br /&gt;
            self._stack.append(m)&lt;br /&gt;
            m = self.arecv(process.ANY)&lt;br /&gt;
&lt;br /&gt;
        if not self._stack:&lt;br /&gt;
            return self.arecv(process.ANY)&lt;br /&gt;
        else:&lt;br /&gt;
            return self._stack.pop()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
                                                0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P1 |P1 |P1 |P1 |   |P2 |P2 |P2 |P2 |P1 |P1 |P1 |P1 |P2 |P2 |P1 |P2 |P2 |P3 |P3 |&lt;br /&gt;
IO    |   |   |   |   |P1 |P1 |   |   |   |P2 |P2 |   |   |P1 |P1 |   |   |   |P2 |P2 |&lt;br /&gt;
SPAWN |P1 |   |   |   |   |P2 |   |   |   |   |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |&lt;br /&gt;
      | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |&lt;br /&gt;
      ---------------------------------------------------------------------------------&lt;br /&gt;
CPU   |P2 |P3 |P3 |   |   |P3 |P3 |P3 |P3 |   |   |P3 |   |   |   |   |   |   |   |   |&lt;br /&gt;
IO    |   |   |   |P3 |P3 |   |   |   |   |P3 |P3 |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
SPAWN |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
# No, non è richiesto. È sufficiente che il controller del dispositivo sia in grado di comunicare con la CPU sul bus e di segnalare il completamente di una delle sue operazioni al momento opportuno. (Il supporto DMA è utile se si vuole affidare la copiatura di grandi quantità di dati dalla memoria secondaria a quella primaria ai controller delle periferiche, e non alla CPU.)&lt;br /&gt;
# Un timer di sistema dotato di interrupt, in grado di notificare il sistema alle scadenze del quanto di tempo.&lt;br /&gt;
# Nessuno, infatti semplicità di realizzazione e basse richieste hardware compaiono tra i suoi principali vantaggi.&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;
&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 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;
&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Tool_per_semafori_e_monitor&amp;diff=2603</id>
		<title>Tool per semafori e monitor</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Tool_per_semafori_e_monitor&amp;diff=2603"/>
		<updated>2020-09-10T18:11:53Z</updated>

		<summary type="html">&lt;p&gt;Acsor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I seguenti archivi forniscono strumenti di programmazione concorrente per i linguaggi C e Python&lt;br /&gt;
&lt;br /&gt;
* [http://www.cs.unibo.it/~renzo/so/tools/sm.tgz Tool per provare i semafori in C]&lt;br /&gt;
* [http://www.cs.unibo.it/~renzo/so/tools/pysm.tgz Tool per provare i semafori in Python]&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2602</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2602"/>
		<updated>2020-09-10T17:46:00Z</updated>

		<summary type="html">&lt;p&gt;Acsor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
&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 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;
&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;
Semaphore mutex = 1;&lt;br /&gt;
&lt;br /&gt;
struct Elem {&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 (da controllare) ===&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;
&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2018&amp;diff=2601</id>
		<title>Prove scritte 2018</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2018&amp;diff=2601"/>
		<updated>2020-09-10T17:40:22Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Controllato e modificato es g.2 esame 21/06/2018&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf Testo dell'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Nello pseudocodice seguente, il termine this fa riferimento al processo corrente, mentre ANY ad uno qualunque.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack&amp;lt;message&amp;gt; messages;&lt;br /&gt;
&lt;br /&gt;
void lifo_send(string m, process dest) {&lt;br /&gt;
	do {&lt;br /&gt;
		asend(m, dest);&lt;br /&gt;
	} while (areceive(dest).text != &amp;quot;ACK&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
message lifo_receive(process source) {&lt;br /&gt;
	if (source != ANY) {&lt;br /&gt;
		message m = areceive(source);&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;ACK&amp;quot;, source);&lt;br /&gt;
&lt;br /&gt;
		return m;&lt;br /&gt;
	} else {&lt;br /&gt;
		message m;&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;END&amp;quot;, this);&lt;br /&gt;
		m = areceive(ANY);&lt;br /&gt;
&lt;br /&gt;
		while (m.text != &amp;quot;END&amp;quot; || m.sender != this) {&lt;br /&gt;
			messages.push(m);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                /* Bisogna tenere conto dei casi in cui lifo_receive() viene invocata quando nessun&lt;br /&gt;
                 * messaggio è stato ancora spedito da altri processi. In tal caso si attende il&lt;br /&gt;
                 * il primo e lo si restituisce.&lt;br /&gt;
                 */&lt;br /&gt;
		if (messages.empty()) {&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			return m;&lt;br /&gt;
		} else {&lt;br /&gt;
			return messages.pop();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&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;
* Visto e corretto dall'utente [[User:Acsor|Acsor]] in data 23/08/2020&lt;br /&gt;
* Visto e corretto dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
class LIFOBuffer {&lt;br /&gt;
	stack&amp;lt;T&amp;gt; s;&lt;br /&gt;
	semaphore mutex(1); // mutua esclusione&lt;br /&gt;
	semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
	void push (T value) {&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		s.push(value);&lt;br /&gt;
                // (1)&lt;br /&gt;
		mutex.V()&lt;br /&gt;
&lt;br /&gt;
		ok2consume.V()  // Curiosità: che succede se spostiamo quest'istruzione in (1)?&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	T pop () {&lt;br /&gt;
		T value;&lt;br /&gt;
&lt;br /&gt;
		ok2consume.P();&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		value = s.pop();&lt;br /&gt;
		mutex.V();&lt;br /&gt;
&lt;br /&gt;
		return value;&lt;br /&gt;
	}&lt;br /&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;
# In sistemi dove dispositivi di archiviazione o supporti hardware per la memoria virtuale (e dunque per la paginazione, spesso utilizzata per realizzare il supporto di memoria virtuale) non sono presenti (es. sistemi embedded). ''(In sistemi real-time la memoria virtuale è praticabile? Annotare.)''&lt;br /&gt;
# 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.&lt;br /&gt;
# Per fornire parallelismo e ridondanza. Non è necessario fare backup dei dati sul disco, nel senso di mantenere una copia identica di dati già memorizzati altrove, in quanto diversi sistemi di codici permettono il rilevamento e/o la correzione di errori.&lt;br /&gt;
# Se in un grafo di Holt multirisorsa esiste un ciclo tra più processi e risorse, ciò non significa che allo stesso tempo non siano coinvolti processi con archi esclusivamente entranti. Ogni processo appartenente a questa categoria non è in attesa di risorse, e può dunque procedere con i suoi calcoli; quando avrà terminato rilascerà le risorse precedentemente allocategli, eventualmente sbloccando uno dei processi coinvolti nel ciclo.&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;
* Visto dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 18:53, 9 September 2020 (CEST). Ritengo sia: corretto (perché l'ho fatto pressappoco uguale). (Ritengo anche che possedere strumenti di analisi formale per verificare la correttezza di codice simile sarebbe di grande ausilio.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
class bounded_semaphore {&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   // serve per significato&lt;br /&gt;
    &lt;br /&gt;
    bounded_semaphore (int initval, unsigned maxval) {&lt;br /&gt;
        value = initval;&lt;br /&gt;
        plus = new semaphore(maxval + initval);&lt;br /&gt;
        minus = new semaphore(maxval - initval);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void P() {&lt;br /&gt;
        plus.P();&lt;br /&gt;
        value--;&lt;br /&gt;
        minus.V(); &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void V() {&lt;br /&gt;
        minus.P();&lt;br /&gt;
        value++;&lt;br /&gt;
        plus.V();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Soluzione &amp;quot;schiacciasassi&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
class bounded_semaphore {&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue&amp;lt;semaphore&amp;gt; okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    unsigned maxval;&lt;br /&gt;
&lt;br /&gt;
    bounded_semaphore (int initval, unsigned maxval) {&lt;br /&gt;
	value = initval;&lt;br /&gt;
        this.maxval = maxval;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
&lt;br /&gt;
        if (value &amp;lt;= -maxval)  {&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;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
    void V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
&lt;br /&gt;
        if (value &amp;gt;= -maxval)  {&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;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]), 23:17, 9 September 2020 (CEST). Ritengo sia: corretto&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10 // Capitale iniziale&lt;br /&gt;
COH = 4,4,4   // Saldo in cassa&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&lt;br /&gt;
 &amp;lt;/nowiki&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&lt;br /&gt;
COH = 1,1,1&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&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Visto e rimaneggiato in data 19:40, 10 September 2020 (CEST) dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;hr&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Il calcolo del working set serve a determinare il numero di processi che possono essere mantenuti attivi sulla base del limite della memoria principale, più precisamente del suo numero di frame. Può essere svolto ad ogni page fault, ossia quando un processo tra quelli attivi richiede una pagina non presente in memoria, o prima di avviare un nuovo processo.&lt;br /&gt;
# 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).&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.&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.&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.&lt;br /&gt;
# Entrambi condividono l'intento di infettare host con codice malevolo, ma differiscono fondamentalmente nella modalità: i virus infettano programmi già esistenti mediante un ''virus dropper'', mentre i worm diffondono copie di se stessi, solitamente attraverso la rete.&lt;br /&gt;
# In vari casi sulla base della natura del sistema. Innanzitutto, in sistemi batch ciò avviene se non sono stati inseriti più processi per un certo lasso di tempo. In sistemi general-purpose (es. per PC o dispositivi mobili) tale condizione è verificabile se tutti i processi sono in attesa su una coda che non è quella dello scheduler (ad. es. di un semaforo o di una periferica di I/O); casi concreti sono pertanto il deadlock (di tutti i processi del sistema) o attesa generale di I/O. Infine sempre in sistemi general-purpose tale condizione può manifestarsi, stavolta in condizioni patologiche, se ogni processo è assegnato ad una propria CPU/core, lasciando pertanto la coda d'attesa vuota.&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;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
proc[x]: x='a',...,'z'&lt;br /&gt;
 while True:&lt;br /&gt;
  //c sarà il carattere stampato dal processo precedente&lt;br /&gt;
  (c, string) = arecv(*)&lt;br /&gt;
  if(string == wait){&lt;br /&gt;
    //mi metto in attesa di ricevere l'ACK da proc[x]&lt;br /&gt;
    m=arecv(x);&lt;br /&gt;
  }&lt;br /&gt;
  if (c == NONE){&lt;br /&gt;
    //significa che sei il primo a ricevere quella stringa&lt;br /&gt;
    print(x);&lt;br /&gt;
    if (len(string) &amp;gt; 1){&lt;br /&gt;
      //mando la wait a tutti, il primo che riceve qualcosa da stampare manda una wait a tutti&lt;br /&gt;
      asend(wait,*);&lt;br /&gt;
      int l = len(string);&lt;br /&gt;
      int i = 1;&lt;br /&gt;
      while(l != 0){&lt;br /&gt;
        asend(proc[string[i]], (x, string[i...]));&lt;br /&gt;
        //si mette in attesa di ricevere l'ACK dal processo dell'ultima lettera della parola&lt;br /&gt;
        m=areceive(proc[string[i]]);&lt;br /&gt;
        //rimando la wait al processo per ribloccarlo&lt;br /&gt;
        asend(wait, proc[string[i]])&lt;br /&gt;
        l--;&lt;br /&gt;
        i++;&lt;br /&gt;
      }&lt;br /&gt;
      //dopo aver finito la stampa della stringa sblocco tutti i processi&lt;br /&gt;
      asend(ACK, *);&lt;br /&gt;
    }&lt;br /&gt;
  }else{&lt;br /&gt;
    print(x);&lt;br /&gt;
    asend(ACK, x);&lt;br /&gt;
    //ricomincia il ciclo while, si rimette in attesa e il 'gestore gli rimanda la wait'&lt;br /&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;
&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;
&lt;br /&gt;
monitor bridge:&lt;br /&gt;
&lt;br /&gt;
    int ncar&lt;br /&gt;
    bool boat_on_0&lt;br /&gt;
    bool boat_on_1       // per semplicità, quando nel codice si trova boat_on_(direction) oppure isBoat(direction)(),&lt;br /&gt;
                         // si valuta il valore booleano di direction e lo si applica sotto forma di stringa al simbolo&lt;br /&gt;
                         // ad esso adiacente&lt;br /&gt;
    bool is_raised&lt;br /&gt;
    queue waiting_mean   // i valori possibili sono: boat0, boat1 oppure car&lt;br /&gt;
    condition ok2go&lt;br /&gt;
  &lt;br /&gt;
    entry car_enter(direction): &lt;br /&gt;
        if is_raised || ncar == MAXCAR:&lt;br /&gt;
            waiting_mean.enqueue(car)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        is_raised = false&lt;br /&gt;
        ++ncar&lt;br /&gt;
  &lt;br /&gt;
    entry car_exit(direction):&lt;br /&gt;
        --ncar&lt;br /&gt;
        if (waiting_mean.top().isBoat() &amp;amp;&amp;amp; ncar == 0) || waiting_mean.top().isCar():    // isBoat ritorna true se l'oggetto su cui&lt;br /&gt;
            waiting_mean.dequeue()                                                      // è invocata è boat0 oppure boat1&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
  &lt;br /&gt;
    entry boat_enter(direction):&lt;br /&gt;
        if !is_raised || boat_on_(direction):&lt;br /&gt;
            waiting_mean.enqueue(boat)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        if waiting_mean.top().isBoat(!direction)():&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
        is_raised = true&lt;br /&gt;
        boat_on_(direction) = true&lt;br /&gt;
  &lt;br /&gt;
    entry boat_exit(direction):&lt;br /&gt;
        boat_on_(direction) = false&lt;br /&gt;
        if !boat_on_(!direction):&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
&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;
=== 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;
entry 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;
entry 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;
entry 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;
entry 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 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge {&lt;br /&gt;
&lt;br /&gt;
  UP=0;&lt;br /&gt;
  DOWN=1;&lt;br /&gt;
  bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
  bool carAreExiting = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2drive;&lt;br /&gt;
  condition ok2barca[2];&lt;br /&gt;
&lt;br /&gt;
  waitingCar = 0;&lt;br /&gt;
  carOnBridge = 0;&lt;br /&gt;
&lt;br /&gt;
  boatWaiting[2] = {0,0};&lt;br /&gt;
  boatIsPassing[2] = {false,false}&lt;br /&gt;
&lt;br /&gt;
  entry car_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == DOWN)&lt;br /&gt;
      if(carOnBridge == MAXCAR)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
      else if (carAreExiting)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
    else &lt;br /&gt;
      if (boatIsPassing[0] || boatIsPassing[1])&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
    carOnBridge++;&lt;br /&gt;
    carAreExiting = false;&lt;br /&gt;
    if(carOnBridge &amp;lt; MAXCAR &amp;amp;&amp;amp; !carAreExiting) &lt;br /&gt;
      ok2drive.signal();&lt;br /&gt;
      &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry car_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    carOnBridge--;&lt;br /&gt;
    carAreExiting = true;&lt;br /&gt;
&lt;br /&gt;
    if(carOnBridge == 0)&lt;br /&gt;
      carAreExiting = false;&lt;br /&gt;
      if(boatWaiting[0] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[0].signal();&lt;br /&gt;
      else if (boatWaiting[1] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[1].signal();&lt;br /&gt;
      else &lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == UP)&lt;br /&gt;
    | if (boatIsPassing[direction] == true)&lt;br /&gt;
    | |  boatWaiting[direction]++;&lt;br /&gt;
    | |  ok2barca.wait();&lt;br /&gt;
    | |  boatWaiting[direction]--;&lt;br /&gt;
    else &lt;br /&gt;
    | if (carOnBridge &amp;gt; 0)&lt;br /&gt;
    | | boatWaiting[direction]++;&lt;br /&gt;
    | | ok2barca.wait();&lt;br /&gt;
    | | boatWaiting[direction]--;&lt;br /&gt;
    | | bridgeis = UP;&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = true;&lt;br /&gt;
&lt;br /&gt;
    if(boatIsPassing[1-direction] == false &amp;amp;&amp;amp; boatWaiting[1-direction] &amp;gt; 0)&lt;br /&gt;
      ok2barca[1-direction].signal();&lt;br /&gt;
    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = false;&lt;br /&gt;
&lt;br /&gt;
    if (boatIsPassing[1-direction] == false)&lt;br /&gt;
      if (waitingCar &amp;gt; 0)&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
    else&lt;br /&gt;
        if (waitingCar == 0)&lt;br /&gt;
          ok2barca[direction].signal();&lt;br /&gt;
          &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&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;
entry 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;
entry 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;
entry 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;
entry 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;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
# (Ri)Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 26/08/2020&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
list printed_msg;  # questa è una variabile condivisa che ai fini dell'esercizio non si può utilizzare (message passing)&lt;br /&gt;
&lt;br /&gt;
process server[i]:&lt;br /&gt;
  while true:&lt;br /&gt;
    &amp;lt;msg, pid&amp;gt; = arecv(*)&lt;br /&gt;
&lt;br /&gt;
    if printed_msg.length == 0 or &amp;lt;msg, pid&amp;gt; is not in printed_msg:&lt;br /&gt;
      printed_msg.append(&amp;lt;msg,id&amp;gt;)&lt;br /&gt;
      print(msg)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
Nello svolgimento seguente, receiver incapsula l'ambiente privato del processo; _peers rappresenta il vettore di processi &amp;quot;fratelli&amp;quot; ai quali può essere chiesto di stampare un messaggio, mentre _printed contiene l'hash di tutti i messaggi stampati dal processo locale. Si suppone che istanze della classe receiver possano essere passate come parametro ad areceive() ed asend() (non implementate).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class receiver:&lt;br /&gt;
    def __init__(self, peers):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param peers: list of processes this process communicates with.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self._peers = tuple(peers)&lt;br /&gt;
        self._printed = list()&lt;br /&gt;
    &lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            process, message = areceive(ANY)&lt;br /&gt;
&lt;br /&gt;
            if process in self._peers:&lt;br /&gt;
                self._reply_query(process, message)&lt;br /&gt;
            else:&lt;br /&gt;
                self._print(process, message)&lt;br /&gt;
&lt;br /&gt;
    def _print(self, sender, message):&lt;br /&gt;
        h = hash(message.text)&lt;br /&gt;
&lt;br /&gt;
        if h not in self._printed and not self._printed_from_peers(message):&lt;br /&gt;
            self._printed.append(h)&lt;br /&gt;
            print(message.text)&lt;br /&gt;
&lt;br /&gt;
    def _reply_query(self, sender, h):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Invoked when the current process receive a &amp;quot;query&amp;quot; from a peer process.&lt;br /&gt;
        `h` contains the hash of a message which may or may have not been&lt;br /&gt;
        sent from this process; if it was sent, the reply is `Yes`, otherwise `No`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        reply = &amp;quot;Yes&amp;quot; if int(h) in self._printed else &amp;quot;No&amp;quot;&lt;br /&gt;
        asend(sender, reply)&lt;br /&gt;
&lt;br /&gt;
    def _printed_from_peers(self, message):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `True` if this message has already been printed from any of the&lt;br /&gt;
        peer processes, `False` otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        h = hash(message)&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            asend(p, str(h))&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            _, reply = areceive(p)&lt;br /&gt;
&lt;br /&gt;
            if reply.text == &amp;quot;Yes&amp;quot;:&lt;br /&gt;
                return True&lt;br /&gt;
            else if reply.text != &amp;quot;No&amp;quot;:&lt;br /&gt;
                # If the response is neither &amp;quot;Yes&amp;quot; nor &amp;quot;No&amp;quot;, then we have got a query&lt;br /&gt;
                self._reply_query(p, reply)&lt;br /&gt;
&lt;br /&gt;
        return False&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Sulla base dei valori in entrata, è possibile costruire le matrici Allocation (q.tà di risorse allocate per processo e per tipo), Need (q.tà di risorse che ogni processo potrebbe ancora chiedere) e il vettore Available (num. di risorse correntemente disponibili).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left&amp;quot;&lt;br /&gt;
! colspan=3 | Allocation&lt;br /&gt;
|-&lt;br /&gt;
   !   !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 4 || 5&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 3 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 2 || 4&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=3 | Need&lt;br /&gt;
|-&lt;br /&gt;
   !    !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 6 || 8&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 6 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 6 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=2 | Available&lt;br /&gt;
|-&lt;br /&gt;
   ! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | x || y&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nel caso delle risorse di tipo A, deve aversi x &amp;gt;= 6 in quanto un processo dovrà essere selezionato come primo nella permutazione dell'algoritmo del banchiere multivaluta, e tutti quelli correnti hanno lo stesso valore Need(i)(1); per ciò che riguarda le risorse di tipo B, possiamo ragionare per esaustione&lt;br /&gt;
&lt;br /&gt;
* Se il primo processo della permutazione è p1, allora y &amp;gt;= 8 (con questo valore posso soddisfare la richiesta di p1 e in seguito tutte le altre)&lt;br /&gt;
* Se il primo processo della permutazione è p2, allora y &amp;gt;= 5: con questo valore è possibile soddisfare la richiesta di p2; una volta che esso avrà finito, restituirà 3 unità della risorsa B, che permetteranno di soddisfare sia le richieste di A sia quelle di C&lt;br /&gt;
* Se il primo processo della permutazione è p3, allora y &amp;gt;= 8 (ragionamento analogo come per p1)&lt;br /&gt;
&lt;br /&gt;
Volendo scegliere il minimo, y &amp;gt;= 5, ed in conclusione (x, y) &amp;gt;= (6, 5).&lt;br /&gt;
&lt;br /&gt;
''Svolgimento basato in parte sull'approccio di Operating System Concepts di Silberschatz. et al, 9th edition, cap. 7.''&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# Può accadere che il sistema torni in uno stato di safety o che invece porti a deadlock. Diversamente uno stato di safety non può portare direttamente ad uno stato di deadlock, ma solo ad uno di non-safety.&lt;br /&gt;
# Selezionare uno o più tra i processi attivi e sospenderli, salvando il loro stato su memoria secondaria operando delle operazioni di swap-out, finché l'insieme dei frame nella memoria centrale non è in grado di soddisfare tutti i processi rimasti attivi.&lt;br /&gt;
# La scelta è determinata perlopiù dal fattore costo. Con un sistema RAID 1 è possibile ripristinare un disco guasto molto brevemente, in quanto le operazioni coinvolte prevedono una semplice ricopiatura dal disco di backup; con un sistema RAID 5 il ripristino del disco guasto deve coinvolgere tutti i dischi dell'intero array, e ciò può richiedere anche ore per dischi di grandi dimensioni. D'altra parte RAID 1 è più costoso (con n dischi, posso memorizzare tanta informazione quanto potrei con n / 2 dischi) rispetto a RAID 5 dove, tra gli n dischi, complessivamente soltanto uno è destinato alle informazioni di ridondanza.&lt;br /&gt;
# ''Completare.''&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2018&amp;diff=2600</id>
		<title>Prove scritte 2018</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2018&amp;diff=2600"/>
		<updated>2020-09-09T21:17:01Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Controllato es g.1 esame 21/06/2018&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf Testo dell'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Nello pseudocodice seguente, il termine this fa riferimento al processo corrente, mentre ANY ad uno qualunque.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack&amp;lt;message&amp;gt; messages;&lt;br /&gt;
&lt;br /&gt;
void lifo_send(string m, process dest) {&lt;br /&gt;
	do {&lt;br /&gt;
		asend(m, dest);&lt;br /&gt;
	} while (areceive(dest).text != &amp;quot;ACK&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
message lifo_receive(process source) {&lt;br /&gt;
	if (source != ANY) {&lt;br /&gt;
		message m = areceive(source);&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;ACK&amp;quot;, source);&lt;br /&gt;
&lt;br /&gt;
		return m;&lt;br /&gt;
	} else {&lt;br /&gt;
		message m;&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;END&amp;quot;, this);&lt;br /&gt;
		m = areceive(ANY);&lt;br /&gt;
&lt;br /&gt;
		while (m.text != &amp;quot;END&amp;quot; || m.sender != this) {&lt;br /&gt;
			messages.push(m);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                /* Bisogna tenere conto dei casi in cui lifo_receive() viene invocata quando nessun&lt;br /&gt;
                 * messaggio è stato ancora spedito da altri processi. In tal caso si attende il&lt;br /&gt;
                 * il primo e lo si restituisce.&lt;br /&gt;
                 */&lt;br /&gt;
		if (messages.empty()) {&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			return m;&lt;br /&gt;
		} else {&lt;br /&gt;
			return messages.pop();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&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;
* Visto e corretto dall'utente [[User:Acsor|Acsor]] in data 23/08/2020&lt;br /&gt;
* Visto e corretto dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
class LIFOBuffer {&lt;br /&gt;
	stack&amp;lt;T&amp;gt; s;&lt;br /&gt;
	semaphore mutex(1); // mutua esclusione&lt;br /&gt;
	semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
	void push (T value) {&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		s.push(value);&lt;br /&gt;
                // (1)&lt;br /&gt;
		mutex.V()&lt;br /&gt;
&lt;br /&gt;
		ok2consume.V()  // Curiosità: che succede se spostiamo quest'istruzione in (1)?&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	T pop () {&lt;br /&gt;
		T value;&lt;br /&gt;
&lt;br /&gt;
		ok2consume.P();&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		value = s.pop();&lt;br /&gt;
		mutex.V();&lt;br /&gt;
&lt;br /&gt;
		return value;&lt;br /&gt;
	}&lt;br /&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;
# In sistemi dove dispositivi di archiviazione o supporti hardware per la memoria virtuale (e dunque per la paginazione, spesso utilizzata per realizzare il supporto di memoria virtuale) non sono presenti (es. sistemi embedded). ''(In sistemi real-time la memoria virtuale è praticabile? Annotare.)''&lt;br /&gt;
# 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.&lt;br /&gt;
# Per fornire parallelismo e ridondanza. Non è necessario fare backup dei dati sul disco, nel senso di mantenere una copia identica di dati già memorizzati altrove, in quanto diversi sistemi di codici permettono il rilevamento e/o la correzione di errori.&lt;br /&gt;
# Se in un grafo di Holt multirisorsa esiste un ciclo tra più processi e risorse, ciò non significa che allo stesso tempo non siano coinvolti processi con archi esclusivamente entranti. Ogni processo appartenente a questa categoria non è in attesa di risorse, e può dunque procedere con i suoi calcoli; quando avrà terminato rilascerà le risorse precedentemente allocategli, eventualmente sbloccando uno dei processi coinvolti nel ciclo.&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;
* Visto dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 18:53, 9 September 2020 (CEST). Ritengo sia: corretto (perché l'ho fatto pressappoco uguale). (Ritengo anche che possedere strumenti di analisi formale per verificare la correttezza di codice simile sarebbe di grande ausilio.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
class bounded_semaphore {&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   // serve per significato&lt;br /&gt;
    &lt;br /&gt;
    bounded_semaphore (int initval, unsigned maxval) {&lt;br /&gt;
        value = initval;&lt;br /&gt;
        plus = new semaphore(maxval + initval);&lt;br /&gt;
        minus = new semaphore(maxval - initval);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void P() {&lt;br /&gt;
        plus.P();&lt;br /&gt;
        value--;&lt;br /&gt;
        minus.V(); &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void V() {&lt;br /&gt;
        minus.P();&lt;br /&gt;
        value++;&lt;br /&gt;
        plus.V();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Soluzione &amp;quot;schiacciasassi&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
class bounded_semaphore {&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue&amp;lt;semaphore&amp;gt; okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    unsigned maxval;&lt;br /&gt;
&lt;br /&gt;
    bounded_semaphore (int initval, unsigned maxval) {&lt;br /&gt;
	value = initval;&lt;br /&gt;
        this.maxval = maxval;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
&lt;br /&gt;
        if (value &amp;lt;= -maxval)  {&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;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
    void V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
&lt;br /&gt;
        if (value &amp;gt;= -maxval)  {&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;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]), 23:17, 9 September 2020 (CEST). Ritengo sia: corretto&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
IC = 10,10,10 // Capitale iniziale&lt;br /&gt;
COH = 4,4,4   // Saldo in cassa&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&lt;br /&gt;
 &amp;lt;/nowiki&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&lt;br /&gt;
COH = 1,1,1&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&lt;br /&gt;
 &amp;lt;/nowiki&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;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
proc[x]: x='a',...,'z'&lt;br /&gt;
 while True:&lt;br /&gt;
  //c sarà il carattere stampato dal processo precedente&lt;br /&gt;
  (c, string) = arecv(*)&lt;br /&gt;
  if(string == wait){&lt;br /&gt;
    //mi metto in attesa di ricevere l'ACK da proc[x]&lt;br /&gt;
    m=arecv(x);&lt;br /&gt;
  }&lt;br /&gt;
  if (c == NONE){&lt;br /&gt;
    //significa che sei il primo a ricevere quella stringa&lt;br /&gt;
    print(x);&lt;br /&gt;
    if (len(string) &amp;gt; 1){&lt;br /&gt;
      //mando la wait a tutti, il primo che riceve qualcosa da stampare manda una wait a tutti&lt;br /&gt;
      asend(wait,*);&lt;br /&gt;
      int l = len(string);&lt;br /&gt;
      int i = 1;&lt;br /&gt;
      while(l != 0){&lt;br /&gt;
        asend(proc[string[i]], (x, string[i...]));&lt;br /&gt;
        //si mette in attesa di ricevere l'ACK dal processo dell'ultima lettera della parola&lt;br /&gt;
        m=areceive(proc[string[i]]);&lt;br /&gt;
        //rimando la wait al processo per ribloccarlo&lt;br /&gt;
        asend(wait, proc[string[i]])&lt;br /&gt;
        l--;&lt;br /&gt;
        i++;&lt;br /&gt;
      }&lt;br /&gt;
      //dopo aver finito la stampa della stringa sblocco tutti i processi&lt;br /&gt;
      asend(ACK, *);&lt;br /&gt;
    }&lt;br /&gt;
  }else{&lt;br /&gt;
    print(x);&lt;br /&gt;
    asend(ACK, x);&lt;br /&gt;
    //ricomincia il ciclo while, si rimette in attesa e il 'gestore gli rimanda la wait'&lt;br /&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;
&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;
&lt;br /&gt;
monitor bridge:&lt;br /&gt;
&lt;br /&gt;
    int ncar&lt;br /&gt;
    bool boat_on_0&lt;br /&gt;
    bool boat_on_1       // per semplicità, quando nel codice si trova boat_on_(direction) oppure isBoat(direction)(),&lt;br /&gt;
                         // si valuta il valore booleano di direction e lo si applica sotto forma di stringa al simbolo&lt;br /&gt;
                         // ad esso adiacente&lt;br /&gt;
    bool is_raised&lt;br /&gt;
    queue waiting_mean   // i valori possibili sono: boat0, boat1 oppure car&lt;br /&gt;
    condition ok2go&lt;br /&gt;
  &lt;br /&gt;
    entry car_enter(direction): &lt;br /&gt;
        if is_raised || ncar == MAXCAR:&lt;br /&gt;
            waiting_mean.enqueue(car)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        is_raised = false&lt;br /&gt;
        ++ncar&lt;br /&gt;
  &lt;br /&gt;
    entry car_exit(direction):&lt;br /&gt;
        --ncar&lt;br /&gt;
        if (waiting_mean.top().isBoat() &amp;amp;&amp;amp; ncar == 0) || waiting_mean.top().isCar():    // isBoat ritorna true se l'oggetto su cui&lt;br /&gt;
            waiting_mean.dequeue()                                                      // è invocata è boat0 oppure boat1&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
  &lt;br /&gt;
    entry boat_enter(direction):&lt;br /&gt;
        if !is_raised || boat_on_(direction):&lt;br /&gt;
            waiting_mean.enqueue(boat)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        if waiting_mean.top().isBoat(!direction)():&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
        is_raised = true&lt;br /&gt;
        boat_on_(direction) = true&lt;br /&gt;
  &lt;br /&gt;
    entry boat_exit(direction):&lt;br /&gt;
        boat_on_(direction) = false&lt;br /&gt;
        if !boat_on_(!direction):&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
&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;
=== 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;
entry 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;
entry 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;
entry 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;
entry 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 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge {&lt;br /&gt;
&lt;br /&gt;
  UP=0;&lt;br /&gt;
  DOWN=1;&lt;br /&gt;
  bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
  bool carAreExiting = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2drive;&lt;br /&gt;
  condition ok2barca[2];&lt;br /&gt;
&lt;br /&gt;
  waitingCar = 0;&lt;br /&gt;
  carOnBridge = 0;&lt;br /&gt;
&lt;br /&gt;
  boatWaiting[2] = {0,0};&lt;br /&gt;
  boatIsPassing[2] = {false,false}&lt;br /&gt;
&lt;br /&gt;
  entry car_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == DOWN)&lt;br /&gt;
      if(carOnBridge == MAXCAR)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
      else if (carAreExiting)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
    else &lt;br /&gt;
      if (boatIsPassing[0] || boatIsPassing[1])&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
    carOnBridge++;&lt;br /&gt;
    carAreExiting = false;&lt;br /&gt;
    if(carOnBridge &amp;lt; MAXCAR &amp;amp;&amp;amp; !carAreExiting) &lt;br /&gt;
      ok2drive.signal();&lt;br /&gt;
      &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry car_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    carOnBridge--;&lt;br /&gt;
    carAreExiting = true;&lt;br /&gt;
&lt;br /&gt;
    if(carOnBridge == 0)&lt;br /&gt;
      carAreExiting = false;&lt;br /&gt;
      if(boatWaiting[0] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[0].signal();&lt;br /&gt;
      else if (boatWaiting[1] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[1].signal();&lt;br /&gt;
      else &lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == UP)&lt;br /&gt;
    | if (boatIsPassing[direction] == true)&lt;br /&gt;
    | |  boatWaiting[direction]++;&lt;br /&gt;
    | |  ok2barca.wait();&lt;br /&gt;
    | |  boatWaiting[direction]--;&lt;br /&gt;
    else &lt;br /&gt;
    | if (carOnBridge &amp;gt; 0)&lt;br /&gt;
    | | boatWaiting[direction]++;&lt;br /&gt;
    | | ok2barca.wait();&lt;br /&gt;
    | | boatWaiting[direction]--;&lt;br /&gt;
    | | bridgeis = UP;&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = true;&lt;br /&gt;
&lt;br /&gt;
    if(boatIsPassing[1-direction] == false &amp;amp;&amp;amp; boatWaiting[1-direction] &amp;gt; 0)&lt;br /&gt;
      ok2barca[1-direction].signal();&lt;br /&gt;
    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = false;&lt;br /&gt;
&lt;br /&gt;
    if (boatIsPassing[1-direction] == false)&lt;br /&gt;
      if (waitingCar &amp;gt; 0)&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
    else&lt;br /&gt;
        if (waitingCar == 0)&lt;br /&gt;
          ok2barca[direction].signal();&lt;br /&gt;
          &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&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;
entry 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;
entry 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;
entry 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;
entry 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;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
# (Ri)Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 26/08/2020&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
list printed_msg;  # questa è una variabile condivisa che ai fini dell'esercizio non si può utilizzare (message passing)&lt;br /&gt;
&lt;br /&gt;
process server[i]:&lt;br /&gt;
  while true:&lt;br /&gt;
    &amp;lt;msg, pid&amp;gt; = arecv(*)&lt;br /&gt;
&lt;br /&gt;
    if printed_msg.length == 0 or &amp;lt;msg, pid&amp;gt; is not in printed_msg:&lt;br /&gt;
      printed_msg.append(&amp;lt;msg,id&amp;gt;)&lt;br /&gt;
      print(msg)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
Nello svolgimento seguente, receiver incapsula l'ambiente privato del processo; _peers rappresenta il vettore di processi &amp;quot;fratelli&amp;quot; ai quali può essere chiesto di stampare un messaggio, mentre _printed contiene l'hash di tutti i messaggi stampati dal processo locale. Si suppone che istanze della classe receiver possano essere passate come parametro ad areceive() ed asend() (non implementate).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class receiver:&lt;br /&gt;
    def __init__(self, peers):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param peers: list of processes this process communicates with.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self._peers = tuple(peers)&lt;br /&gt;
        self._printed = list()&lt;br /&gt;
    &lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            process, message = areceive(ANY)&lt;br /&gt;
&lt;br /&gt;
            if process in self._peers:&lt;br /&gt;
                self._reply_query(process, message)&lt;br /&gt;
            else:&lt;br /&gt;
                self._print(process, message)&lt;br /&gt;
&lt;br /&gt;
    def _print(self, sender, message):&lt;br /&gt;
        h = hash(message.text)&lt;br /&gt;
&lt;br /&gt;
        if h not in self._printed and not self._printed_from_peers(message):&lt;br /&gt;
            self._printed.append(h)&lt;br /&gt;
            print(message.text)&lt;br /&gt;
&lt;br /&gt;
    def _reply_query(self, sender, h):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Invoked when the current process receive a &amp;quot;query&amp;quot; from a peer process.&lt;br /&gt;
        `h` contains the hash of a message which may or may have not been&lt;br /&gt;
        sent from this process; if it was sent, the reply is `Yes`, otherwise `No`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        reply = &amp;quot;Yes&amp;quot; if int(h) in self._printed else &amp;quot;No&amp;quot;&lt;br /&gt;
        asend(sender, reply)&lt;br /&gt;
&lt;br /&gt;
    def _printed_from_peers(self, message):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `True` if this message has already been printed from any of the&lt;br /&gt;
        peer processes, `False` otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        h = hash(message)&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            asend(p, str(h))&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            _, reply = areceive(p)&lt;br /&gt;
&lt;br /&gt;
            if reply.text == &amp;quot;Yes&amp;quot;:&lt;br /&gt;
                return True&lt;br /&gt;
            else if reply.text != &amp;quot;No&amp;quot;:&lt;br /&gt;
                # If the response is neither &amp;quot;Yes&amp;quot; nor &amp;quot;No&amp;quot;, then we have got a query&lt;br /&gt;
                self._reply_query(p, reply)&lt;br /&gt;
&lt;br /&gt;
        return False&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Sulla base dei valori in entrata, è possibile costruire le matrici Allocation (q.tà di risorse allocate per processo e per tipo), Need (q.tà di risorse che ogni processo potrebbe ancora chiedere) e il vettore Available (num. di risorse correntemente disponibili).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left&amp;quot;&lt;br /&gt;
! colspan=3 | Allocation&lt;br /&gt;
|-&lt;br /&gt;
   !   !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 4 || 5&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 3 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 2 || 4&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=3 | Need&lt;br /&gt;
|-&lt;br /&gt;
   !    !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 6 || 8&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 6 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 6 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=2 | Available&lt;br /&gt;
|-&lt;br /&gt;
   ! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | x || y&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nel caso delle risorse di tipo A, deve aversi x &amp;gt;= 6 in quanto un processo dovrà essere selezionato come primo nella permutazione dell'algoritmo del banchiere multivaluta, e tutti quelli correnti hanno lo stesso valore Need(i)(1); per ciò che riguarda le risorse di tipo B, possiamo ragionare per esaustione&lt;br /&gt;
&lt;br /&gt;
* Se il primo processo della permutazione è p1, allora y &amp;gt;= 8 (con questo valore posso soddisfare la richiesta di p1 e in seguito tutte le altre)&lt;br /&gt;
* Se il primo processo della permutazione è p2, allora y &amp;gt;= 5: con questo valore è possibile soddisfare la richiesta di p2; una volta che esso avrà finito, restituirà 3 unità della risorsa B, che permetteranno di soddisfare sia le richieste di A sia quelle di C&lt;br /&gt;
* Se il primo processo della permutazione è p3, allora y &amp;gt;= 8 (ragionamento analogo come per p1)&lt;br /&gt;
&lt;br /&gt;
Volendo scegliere il minimo, y &amp;gt;= 5, ed in conclusione (x, y) &amp;gt;= (6, 5).&lt;br /&gt;
&lt;br /&gt;
''Svolgimento basato in parte sull'approccio di Operating System Concepts di Silberschatz. et al, 9th edition, cap. 7.''&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# Può accadere che il sistema torni in uno stato di safety o che invece porti a deadlock. Diversamente uno stato di safety non può portare direttamente ad uno stato di deadlock, ma solo ad uno di non-safety.&lt;br /&gt;
# Selezionare uno o più tra i processi attivi e sospenderli, salvando il loro stato su memoria secondaria operando delle operazioni di swap-out, finché l'insieme dei frame nella memoria centrale non è in grado di soddisfare tutti i processi rimasti attivi.&lt;br /&gt;
# La scelta è determinata perlopiù dal fattore costo. Con un sistema RAID 1 è possibile ripristinare un disco guasto molto brevemente, in quanto le operazioni coinvolte prevedono una semplice ricopiatura dal disco di backup; con un sistema RAID 5 il ripristino del disco guasto deve coinvolgere tutti i dischi dell'intero array, e ciò può richiedere anche ore per dischi di grandi dimensioni. D'altra parte RAID 1 è più costoso (con n dischi, posso memorizzare tanta informazione quanto potrei con n / 2 dischi) rispetto a RAID 5 dove, tra gli n dischi, complessivamente soltanto uno è destinato alle informazioni di ridondanza.&lt;br /&gt;
# ''Completare.''&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2018&amp;diff=2599</id>
		<title>Prove scritte 2018</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2018&amp;diff=2599"/>
		<updated>2020-09-09T16:53:25Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Peer-review sull'es. c2 del 21/06/2018&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf Testo dell'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Nello pseudocodice seguente, il termine this fa riferimento al processo corrente, mentre ANY ad uno qualunque.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack&amp;lt;message&amp;gt; messages;&lt;br /&gt;
&lt;br /&gt;
void lifo_send(string m, process dest) {&lt;br /&gt;
	do {&lt;br /&gt;
		asend(m, dest);&lt;br /&gt;
	} while (areceive(dest).text != &amp;quot;ACK&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
message lifo_receive(process source) {&lt;br /&gt;
	if (source != ANY) {&lt;br /&gt;
		message m = areceive(source);&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;ACK&amp;quot;, source);&lt;br /&gt;
&lt;br /&gt;
		return m;&lt;br /&gt;
	} else {&lt;br /&gt;
		message m;&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;END&amp;quot;, this);&lt;br /&gt;
		m = areceive(ANY);&lt;br /&gt;
&lt;br /&gt;
		while (m.text != &amp;quot;END&amp;quot; || m.sender != this) {&lt;br /&gt;
			messages.push(m);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                /* Bisogna tenere conto dei casi in cui lifo_receive() viene invocata quando nessun&lt;br /&gt;
                 * messaggio è stato ancora spedito da altri processi. In tal caso si attende il&lt;br /&gt;
                 * il primo e lo si restituisce.&lt;br /&gt;
                 */&lt;br /&gt;
		if (messages.empty()) {&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			return m;&lt;br /&gt;
		} else {&lt;br /&gt;
			return messages.pop();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&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;
* Visto e corretto dall'utente [[User:Acsor|Acsor]] in data 23/08/2020&lt;br /&gt;
* Visto e corretto dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
class LIFOBuffer {&lt;br /&gt;
	stack&amp;lt;T&amp;gt; s;&lt;br /&gt;
	semaphore mutex(1); // mutua esclusione&lt;br /&gt;
	semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
	void push (T value) {&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		s.push(value);&lt;br /&gt;
                // (1)&lt;br /&gt;
		mutex.V()&lt;br /&gt;
&lt;br /&gt;
		ok2consume.V()  // Curiosità: che succede se spostiamo quest'istruzione in (1)?&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	T pop () {&lt;br /&gt;
		T value;&lt;br /&gt;
&lt;br /&gt;
		ok2consume.P();&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		value = s.pop();&lt;br /&gt;
		mutex.V();&lt;br /&gt;
&lt;br /&gt;
		return value;&lt;br /&gt;
	}&lt;br /&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;
# In sistemi dove dispositivi di archiviazione o supporti hardware per la memoria virtuale (e dunque per la paginazione, spesso utilizzata per realizzare il supporto di memoria virtuale) non sono presenti (es. sistemi embedded). ''(In sistemi real-time la memoria virtuale è praticabile? Annotare.)''&lt;br /&gt;
# 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.&lt;br /&gt;
# Per fornire parallelismo e ridondanza. Non è necessario fare backup dei dati sul disco, nel senso di mantenere una copia identica di dati già memorizzati altrove, in quanto diversi sistemi di codici permettono il rilevamento e/o la correzione di errori.&lt;br /&gt;
# Se in un grafo di Holt multirisorsa esiste un ciclo tra più processi e risorse, ciò non significa che allo stesso tempo non siano coinvolti processi con archi esclusivamente entranti. Ogni processo appartenente a questa categoria non è in attesa di risorse, e può dunque procedere con i suoi calcoli; quando avrà terminato rilascerà le risorse precedentemente allocategli, eventualmente sbloccando uno dei processi coinvolti nel ciclo.&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;
* Visto dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 18:53, 9 September 2020 (CEST). Ritengo sia: corretto (perché l'ho fatto pressappoco uguale). (Ritengo anche che possedere strumenti di analisi formale per verificare la correttezza di codice simile sarebbe di grande ausilio.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
class bounded_semaphore {&lt;br /&gt;
    semaphore plus;&lt;br /&gt;
    semaphore minus;&lt;br /&gt;
    int value;   // serve per significato&lt;br /&gt;
    &lt;br /&gt;
    bounded_semaphore (int initval, unsigned maxval) {&lt;br /&gt;
        value = initval;&lt;br /&gt;
        plus = new semaphore(maxval + initval);&lt;br /&gt;
        minus = new semaphore(maxval - initval);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void P() {&lt;br /&gt;
        plus.P();&lt;br /&gt;
        value--;&lt;br /&gt;
        minus.V(); &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void V() {&lt;br /&gt;
        minus.P();&lt;br /&gt;
        value++;&lt;br /&gt;
        plus.V();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Soluzione &amp;quot;schiacciasassi&amp;quot; ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
class bounded_semaphore {&lt;br /&gt;
    semaphore mutex;&lt;br /&gt;
    queue&amp;lt;semaphore&amp;gt; okmin, okmax;&lt;br /&gt;
    int value;&lt;br /&gt;
    unsigned maxval;&lt;br /&gt;
&lt;br /&gt;
    bounded_semaphore (int initval, unsigned maxval) {&lt;br /&gt;
	value = initval;&lt;br /&gt;
        this.maxval = maxval;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    void P() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
&lt;br /&gt;
        if (value &amp;lt;= -maxval)  {&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;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
    void V() {&lt;br /&gt;
        mutex.P();&lt;br /&gt;
&lt;br /&gt;
        if (value &amp;gt;= -maxval)  {&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;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
&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;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
proc[x]: x='a',...,'z'&lt;br /&gt;
 while True:&lt;br /&gt;
  //c sarà il carattere stampato dal processo precedente&lt;br /&gt;
  (c, string) = arecv(*)&lt;br /&gt;
  if(string == wait){&lt;br /&gt;
    //mi metto in attesa di ricevere l'ACK da proc[x]&lt;br /&gt;
    m=arecv(x);&lt;br /&gt;
  }&lt;br /&gt;
  if (c == NONE){&lt;br /&gt;
    //significa che sei il primo a ricevere quella stringa&lt;br /&gt;
    print(x);&lt;br /&gt;
    if (len(string) &amp;gt; 1){&lt;br /&gt;
      //mando la wait a tutti, il primo che riceve qualcosa da stampare manda una wait a tutti&lt;br /&gt;
      asend(wait,*);&lt;br /&gt;
      int l = len(string);&lt;br /&gt;
      int i = 1;&lt;br /&gt;
      while(l != 0){&lt;br /&gt;
        asend(proc[string[i]], (x, string[i...]));&lt;br /&gt;
        //si mette in attesa di ricevere l'ACK dal processo dell'ultima lettera della parola&lt;br /&gt;
        m=areceive(proc[string[i]]);&lt;br /&gt;
        //rimando la wait al processo per ribloccarlo&lt;br /&gt;
        asend(wait, proc[string[i]])&lt;br /&gt;
        l--;&lt;br /&gt;
        i++;&lt;br /&gt;
      }&lt;br /&gt;
      //dopo aver finito la stampa della stringa sblocco tutti i processi&lt;br /&gt;
      asend(ACK, *);&lt;br /&gt;
    }&lt;br /&gt;
  }else{&lt;br /&gt;
    print(x);&lt;br /&gt;
    asend(ACK, x);&lt;br /&gt;
    //ricomincia il ciclo while, si rimette in attesa e il 'gestore gli rimanda la wait'&lt;br /&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;
&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;
&lt;br /&gt;
monitor bridge:&lt;br /&gt;
&lt;br /&gt;
    int ncar&lt;br /&gt;
    bool boat_on_0&lt;br /&gt;
    bool boat_on_1       // per semplicità, quando nel codice si trova boat_on_(direction) oppure isBoat(direction)(),&lt;br /&gt;
                         // si valuta il valore booleano di direction e lo si applica sotto forma di stringa al simbolo&lt;br /&gt;
                         // ad esso adiacente&lt;br /&gt;
    bool is_raised&lt;br /&gt;
    queue waiting_mean   // i valori possibili sono: boat0, boat1 oppure car&lt;br /&gt;
    condition ok2go&lt;br /&gt;
  &lt;br /&gt;
    entry car_enter(direction): &lt;br /&gt;
        if is_raised || ncar == MAXCAR:&lt;br /&gt;
            waiting_mean.enqueue(car)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        is_raised = false&lt;br /&gt;
        ++ncar&lt;br /&gt;
  &lt;br /&gt;
    entry car_exit(direction):&lt;br /&gt;
        --ncar&lt;br /&gt;
        if (waiting_mean.top().isBoat() &amp;amp;&amp;amp; ncar == 0) || waiting_mean.top().isCar():    // isBoat ritorna true se l'oggetto su cui&lt;br /&gt;
            waiting_mean.dequeue()                                                      // è invocata è boat0 oppure boat1&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
  &lt;br /&gt;
    entry boat_enter(direction):&lt;br /&gt;
        if !is_raised || boat_on_(direction):&lt;br /&gt;
            waiting_mean.enqueue(boat)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        if waiting_mean.top().isBoat(!direction)():&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
        is_raised = true&lt;br /&gt;
        boat_on_(direction) = true&lt;br /&gt;
  &lt;br /&gt;
    entry boat_exit(direction):&lt;br /&gt;
        boat_on_(direction) = false&lt;br /&gt;
        if !boat_on_(!direction):&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
&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;
=== 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;
entry 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;
entry 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;
entry 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;
entry 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 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge {&lt;br /&gt;
&lt;br /&gt;
  UP=0;&lt;br /&gt;
  DOWN=1;&lt;br /&gt;
  bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
  bool carAreExiting = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2drive;&lt;br /&gt;
  condition ok2barca[2];&lt;br /&gt;
&lt;br /&gt;
  waitingCar = 0;&lt;br /&gt;
  carOnBridge = 0;&lt;br /&gt;
&lt;br /&gt;
  boatWaiting[2] = {0,0};&lt;br /&gt;
  boatIsPassing[2] = {false,false}&lt;br /&gt;
&lt;br /&gt;
  entry car_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == DOWN)&lt;br /&gt;
      if(carOnBridge == MAXCAR)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
      else if (carAreExiting)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
    else &lt;br /&gt;
      if (boatIsPassing[0] || boatIsPassing[1])&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
    carOnBridge++;&lt;br /&gt;
    carAreExiting = false;&lt;br /&gt;
    if(carOnBridge &amp;lt; MAXCAR &amp;amp;&amp;amp; !carAreExiting) &lt;br /&gt;
      ok2drive.signal();&lt;br /&gt;
      &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry car_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    carOnBridge--;&lt;br /&gt;
    carAreExiting = true;&lt;br /&gt;
&lt;br /&gt;
    if(carOnBridge == 0)&lt;br /&gt;
      carAreExiting = false;&lt;br /&gt;
      if(boatWaiting[0] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[0].signal();&lt;br /&gt;
      else if (boatWaiting[1] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[1].signal();&lt;br /&gt;
      else &lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == UP)&lt;br /&gt;
    | if (boatIsPassing[direction] == true)&lt;br /&gt;
    | |  boatWaiting[direction]++;&lt;br /&gt;
    | |  ok2barca.wait();&lt;br /&gt;
    | |  boatWaiting[direction]--;&lt;br /&gt;
    else &lt;br /&gt;
    | if (carOnBridge &amp;gt; 0)&lt;br /&gt;
    | | boatWaiting[direction]++;&lt;br /&gt;
    | | ok2barca.wait();&lt;br /&gt;
    | | boatWaiting[direction]--;&lt;br /&gt;
    | | bridgeis = UP;&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = true;&lt;br /&gt;
&lt;br /&gt;
    if(boatIsPassing[1-direction] == false &amp;amp;&amp;amp; boatWaiting[1-direction] &amp;gt; 0)&lt;br /&gt;
      ok2barca[1-direction].signal();&lt;br /&gt;
    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = false;&lt;br /&gt;
&lt;br /&gt;
    if (boatIsPassing[1-direction] == false)&lt;br /&gt;
      if (waitingCar &amp;gt; 0)&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
    else&lt;br /&gt;
        if (waitingCar == 0)&lt;br /&gt;
          ok2barca[direction].signal();&lt;br /&gt;
          &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&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;
entry 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;
entry 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;
entry 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;
entry 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;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
# (Ri)Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 26/08/2020&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
list printed_msg;  # questa è una variabile condivisa che ai fini dell'esercizio non si può utilizzare (message passing)&lt;br /&gt;
&lt;br /&gt;
process server[i]:&lt;br /&gt;
  while true:&lt;br /&gt;
    &amp;lt;msg, pid&amp;gt; = arecv(*)&lt;br /&gt;
&lt;br /&gt;
    if printed_msg.length == 0 or &amp;lt;msg, pid&amp;gt; is not in printed_msg:&lt;br /&gt;
      printed_msg.append(&amp;lt;msg,id&amp;gt;)&lt;br /&gt;
      print(msg)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
Nello svolgimento seguente, receiver incapsula l'ambiente privato del processo; _peers rappresenta il vettore di processi &amp;quot;fratelli&amp;quot; ai quali può essere chiesto di stampare un messaggio, mentre _printed contiene l'hash di tutti i messaggi stampati dal processo locale. Si suppone che istanze della classe receiver possano essere passate come parametro ad areceive() ed asend() (non implementate).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class receiver:&lt;br /&gt;
    def __init__(self, peers):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param peers: list of processes this process communicates with.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self._peers = tuple(peers)&lt;br /&gt;
        self._printed = list()&lt;br /&gt;
    &lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            process, message = areceive(ANY)&lt;br /&gt;
&lt;br /&gt;
            if process in self._peers:&lt;br /&gt;
                self._reply_query(process, message)&lt;br /&gt;
            else:&lt;br /&gt;
                self._print(process, message)&lt;br /&gt;
&lt;br /&gt;
    def _print(self, sender, message):&lt;br /&gt;
        h = hash(message.text)&lt;br /&gt;
&lt;br /&gt;
        if h not in self._printed and not self._printed_from_peers(message):&lt;br /&gt;
            self._printed.append(h)&lt;br /&gt;
            print(message.text)&lt;br /&gt;
&lt;br /&gt;
    def _reply_query(self, sender, h):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Invoked when the current process receive a &amp;quot;query&amp;quot; from a peer process.&lt;br /&gt;
        `h` contains the hash of a message which may or may have not been&lt;br /&gt;
        sent from this process; if it was sent, the reply is `Yes`, otherwise `No`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        reply = &amp;quot;Yes&amp;quot; if int(h) in self._printed else &amp;quot;No&amp;quot;&lt;br /&gt;
        asend(sender, reply)&lt;br /&gt;
&lt;br /&gt;
    def _printed_from_peers(self, message):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `True` if this message has already been printed from any of the&lt;br /&gt;
        peer processes, `False` otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        h = hash(message)&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            asend(p, str(h))&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            _, reply = areceive(p)&lt;br /&gt;
&lt;br /&gt;
            if reply.text == &amp;quot;Yes&amp;quot;:&lt;br /&gt;
                return True&lt;br /&gt;
            else if reply.text != &amp;quot;No&amp;quot;:&lt;br /&gt;
                # If the response is neither &amp;quot;Yes&amp;quot; nor &amp;quot;No&amp;quot;, then we have got a query&lt;br /&gt;
                self._reply_query(p, reply)&lt;br /&gt;
&lt;br /&gt;
        return False&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Sulla base dei valori in entrata, è possibile costruire le matrici Allocation (q.tà di risorse allocate per processo e per tipo), Need (q.tà di risorse che ogni processo potrebbe ancora chiedere) e il vettore Available (num. di risorse correntemente disponibili).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left&amp;quot;&lt;br /&gt;
! colspan=3 | Allocation&lt;br /&gt;
|-&lt;br /&gt;
   !   !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 4 || 5&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 3 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 2 || 4&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=3 | Need&lt;br /&gt;
|-&lt;br /&gt;
   !    !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 6 || 8&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 6 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 6 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=2 | Available&lt;br /&gt;
|-&lt;br /&gt;
   ! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | x || y&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nel caso delle risorse di tipo A, deve aversi x &amp;gt;= 6 in quanto un processo dovrà essere selezionato come primo nella permutazione dell'algoritmo del banchiere multivaluta, e tutti quelli correnti hanno lo stesso valore Need(i)(1); per ciò che riguarda le risorse di tipo B, possiamo ragionare per esaustione&lt;br /&gt;
&lt;br /&gt;
* Se il primo processo della permutazione è p1, allora y &amp;gt;= 8 (con questo valore posso soddisfare la richiesta di p1 e in seguito tutte le altre)&lt;br /&gt;
* Se il primo processo della permutazione è p2, allora y &amp;gt;= 5: con questo valore è possibile soddisfare la richiesta di p2; una volta che esso avrà finito, restituirà 3 unità della risorsa B, che permetteranno di soddisfare sia le richieste di A sia quelle di C&lt;br /&gt;
* Se il primo processo della permutazione è p3, allora y &amp;gt;= 8 (ragionamento analogo come per p1)&lt;br /&gt;
&lt;br /&gt;
Volendo scegliere il minimo, y &amp;gt;= 5, ed in conclusione (x, y) &amp;gt;= (6, 5).&lt;br /&gt;
&lt;br /&gt;
''Svolgimento basato in parte sull'approccio di Operating System Concepts di Silberschatz. et al, 9th edition, cap. 7.''&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# Può accadere che il sistema torni in uno stato di safety o che invece porti a deadlock. Diversamente uno stato di safety non può portare direttamente ad uno stato di deadlock, ma solo ad uno di non-safety.&lt;br /&gt;
# Selezionare uno o più tra i processi attivi e sospenderli, salvando il loro stato su memoria secondaria operando delle operazioni di swap-out, finché l'insieme dei frame nella memoria centrale non è in grado di soddisfare tutti i processi rimasti attivi.&lt;br /&gt;
# La scelta è determinata perlopiù dal fattore costo. Con un sistema RAID 1 è possibile ripristinare un disco guasto molto brevemente, in quanto le operazioni coinvolte prevedono una semplice ricopiatura dal disco di backup; con un sistema RAID 5 il ripristino del disco guasto deve coinvolgere tutti i dischi dell'intero array, e ciò può richiedere anche ore per dischi di grandi dimensioni. D'altra parte RAID 1 è più costoso (con n dischi, posso memorizzare tanta informazione quanto potrei con n / 2 dischi) rispetto a RAID 5 dove, tra gli n dischi, complessivamente soltanto uno è destinato alle informazioni di ridondanza.&lt;br /&gt;
# ''Completare.''&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2598</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2598"/>
		<updated>2020-09-04T10:26:24Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Svolto es c.2 esame 15/07/2019&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
        altri operai in attesa.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 16:03, 2 September 2020 (CEST). Ritengo sia: corretto&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (controllato) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
&lt;br /&gt;
        if (message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(), dummy) # self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
&lt;br /&gt;
        if (message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
Viene ritornata x stessa, in un numero di iterazioni pari a length(x). Il calcolo viene svolto tramite message passing tra processi client e processo server; [http://www.treccani.it/magazine/lingua_italiana/domande_e_risposte/grammatica/grammatica_030.html quest'ultimo] opera una sorta di iterazione inoltrando a se stesso il messaggio spedito da un client finché x != &amp;quot;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Se più processi chiamano la funzione dilemma() allo stesso tempo, ciò non causa disagi nel calcolo del risultato finale. Infatti l'identificatore del processo cliente destinatario è memorizzato in pid, e protratto fino alla chiamata in cui x == &amp;quot;&amp;quot;. Inoltre la presenza di molteplici richieste non causa sovrapposizione, posto che asend() memorizzi il contenuto di messaggi in sospeso in una coda FIFO.&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (controllato) ===&lt;br /&gt;
* Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 19:13, 1 September 2020 (CEST). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il programma è composto da due processi, ognuno dei quali stampa all'infinito il proprio identificatore. Perché sia possibile stampare è però necessario attendere il proprio turno, condizione gestita dal monitor bohm: esso possiede due stati (0 o 1) ed è possibile entrarvi quando l'id del processo invocante e il valore dello stato corrispondono; la procedura post() di bohm setta lo stato al valore complementare e sveglia il processo in attesa sulla coda di condizione corrispondente (al nuovo stato). &lt;br /&gt;
&lt;br /&gt;
È possibile implementare il meccanismo di sincronizzazione con semafori tramite il codice seguente&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
binary_sempahore[2] sem = {new binary_semaphore(1), new binary_semaphore(0)};&lt;br /&gt;
&lt;br /&gt;
void pre (int n) {&lt;br /&gt;
    sem[n].P();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void post (int n) {&lt;br /&gt;
    sem[1 - n].V();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Date le variabili del problema x, y ed m, bisogna avere x &amp;lt; m, x &amp;lt; y e che il tempo di arrivo dei processi P1, P2 e P3 durante lo scheduling RR sia P1, P2 e P3. Per ulteriori informazioni vedere lo svolgimento in figura. (Nota: non è specificata la relazione tra y ed m né sono considerati i casi x = m e x = y.)&lt;br /&gt;
&lt;br /&gt;
[[File:2019-09-13-g1.jpg | 768px]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Le opzioni per comunicare con le periferiche di IO sono solitamente due: polling (sondaggio) e interrupt. Mediante il polling il sistema verifica costantemente lo stato dei dispositivi di IO prendendo azione quando esso cambia, con gli interrupt sono i dispositivi stessi a notificare il cambiamento del loro stato. Poiché fare polling significa eseguire ciclicamente delle istruzioni che svolgano il controllo, ricevere degli interrupt è più efficiente perché nello stesso tempo è possibile svolgere altro lavoro utile.&lt;br /&gt;
# ''Da svolgere.''&lt;br /&gt;
# Quando bisogna svolgere un'operazione di swap-in (caricamento di una pagina dalla memoria secondaria a quella primaria) e di swap-out (inversa alla precedente). L'algoritmo di rimpiazzamento è invocato durante un'operazione di swap-in che vede la memoria centrale completamente occupata: in tal caso sarà necessario individuare una pagina da spostare in memoria secondaria.&lt;br /&gt;
# Vantaggi: dimensioni del file eseguibile finale ridotte, in quanto non è richiesto mantenere all'interno dello stesso una copia delle procedure di cui ci si serve; risparmio in memoria centrale: per un dato simbolo appartenente ad una data libreria, è possibile riservare un solo spazio in memoria condiviso da più processi che ne hanno bisogno. Svantaggi: versionamento, ovvero l'installazione di versioni più aggiornate della stessa libreria in conflitto con quelle meno recenti: tale problema è risolto mediante la definizione precisa di numeri di versione delle librerie e la specificazione delle dipendenze (rispetto ad un dato numero di versione).&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2597</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2597"/>
		<updated>2020-09-03T21:23:31Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Svolo es. g2 dell'esame 13/09/2019&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
        altri operai in attesa.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 16:03, 2 September 2020 (CEST). Ritengo sia: corretto&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (controllato) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
&lt;br /&gt;
        if (message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(), dummy) # self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
&lt;br /&gt;
        if (message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (controllato) ===&lt;br /&gt;
* Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 19:13, 1 September 2020 (CEST). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il programma è composto da due processi, ognuno dei quali stampa all'infinito il proprio identificatore. Perché sia possibile stampare è però necessario attendere il proprio turno, condizione gestita dal monitor bohm: esso possiede due stati (0 o 1) ed è possibile entrarvi quando l'id del processo invocante e il valore dello stato corrispondono; la procedura post() di bohm setta lo stato al valore complementare e sveglia il processo in attesa sulla coda di condizione corrispondente (al nuovo stato). &lt;br /&gt;
&lt;br /&gt;
È possibile implementare il meccanismo di sincronizzazione con semafori tramite il codice seguente&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
binary_sempahore[2] sem = {new binary_semaphore(1), new binary_semaphore(0)};&lt;br /&gt;
&lt;br /&gt;
void pre (int n) {&lt;br /&gt;
    sem[n].P();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void post (int n) {&lt;br /&gt;
    sem[1 - n].V();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Date le variabili del problema x, y ed m, bisogna avere x &amp;lt; m, x &amp;lt; y e che il tempo di arrivo dei processi P1, P2 e P3 durante lo scheduling RR sia P1, P2 e P3. Per ulteriori informazioni vedere lo svolgimento in figura. (Nota: non è specificata la relazione tra y ed m né sono considerati i casi x = m e x = y.)&lt;br /&gt;
&lt;br /&gt;
[[File:2019-09-13-g1.jpg | 768px]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Le opzioni per comunicare con le periferiche di IO sono solitamente due: polling (sondaggio) e interrupt. Mediante il polling il sistema verifica costantemente lo stato dei dispositivi di IO prendendo azione quando esso cambia, con gli interrupt sono i dispositivi stessi a notificare il cambiamento del loro stato. Poiché fare polling significa eseguire ciclicamente delle istruzioni che svolgano il controllo, ricevere degli interrupt è più efficiente perché nello stesso tempo è possibile svolgere altro lavoro utile.&lt;br /&gt;
# ''Da svolgere.''&lt;br /&gt;
# Quando bisogna svolgere un'operazione di swap-in (caricamento di una pagina dalla memoria secondaria a quella primaria) e di swap-out (inversa alla precedente). L'algoritmo di rimpiazzamento è invocato durante un'operazione di swap-in che vede la memoria centrale completamente occupata: in tal caso sarà necessario individuare una pagina da spostare in memoria secondaria.&lt;br /&gt;
# Vantaggi: dimensioni del file eseguibile finale ridotte, in quanto non è richiesto mantenere all'interno dello stesso una copia delle procedure di cui ci si serve; risparmio in memoria centrale: per un dato simbolo appartenente ad una data libreria, è possibile riservare un solo spazio in memoria condiviso da più processi che ne hanno bisogno. Svantaggi: versionamento, ovvero l'installazione di versioni più aggiornate della stessa libreria in conflitto con quelle meno recenti: tale problema è risolto mediante la definizione precisa di numeri di versione delle librerie e la specificazione delle dipendenze (rispetto ad un dato numero di versione).&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2596</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2596"/>
		<updated>2020-09-03T21:17:37Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Svolto es. g1 dell'esame 13/09/2019&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
        altri operai in attesa.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 16:03, 2 September 2020 (CEST). Ritengo sia: corretto&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (controllato) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
&lt;br /&gt;
        if (message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(), dummy) # self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
&lt;br /&gt;
        if (message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (controllato) ===&lt;br /&gt;
* Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 19:13, 1 September 2020 (CEST). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il programma è composto da due processi, ognuno dei quali stampa all'infinito il proprio identificatore. Perché sia possibile stampare è però necessario attendere il proprio turno, condizione gestita dal monitor bohm: esso possiede due stati (0 o 1) ed è possibile entrarvi quando l'id del processo invocante e il valore dello stato corrispondono; la procedura post() di bohm setta lo stato al valore complementare e sveglia il processo in attesa sulla coda di condizione corrispondente (al nuovo stato). &lt;br /&gt;
&lt;br /&gt;
È possibile implementare il meccanismo di sincronizzazione con semafori tramite il codice seguente&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
binary_sempahore[2] sem = {new binary_semaphore(1), new binary_semaphore(0)};&lt;br /&gt;
&lt;br /&gt;
void pre (int n) {&lt;br /&gt;
    sem[n].P();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void post (int n) {&lt;br /&gt;
    sem[1 - n].V();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Date le variabili del problema x, y ed m, bisogna avere x &amp;lt; m, x &amp;lt; y e che il tempo di arrivo dei processi P1, P2 e P3 durante lo scheduling RR sia P1, P2 e P3. Per ulteriori informazioni vedere lo svolgimento in figura. (Nota: non è specificata la relazione tra y ed m né sono considerati i casi x = m e x = y.)&lt;br /&gt;
&lt;br /&gt;
[[File:2019-09-13-g1.jpg | 768px ]]&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=File:2019-09-13-g1.jpg&amp;diff=2595</id>
		<title>File:2019-09-13-g1.jpg</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=File:2019-09-13-g1.jpg&amp;diff=2595"/>
		<updated>2020-09-03T21:14:52Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Acsor uploaded a new version of &amp;amp;quot;File:2019-09-13-g1.jpg&amp;amp;quot;: Reverted to version as of 20:38, 3 September 2020&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Esercizio g1 dell'esame del 2019/09/13.&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=File:2019-09-13-g1.jpg&amp;diff=2594</id>
		<title>File:2019-09-13-g1.jpg</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=File:2019-09-13-g1.jpg&amp;diff=2594"/>
		<updated>2020-09-03T21:14:19Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Acsor uploaded a new version of &amp;amp;quot;File:2019-09-13-g1.jpg&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Esercizio g1 dell'esame del 2019/09/13.&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=File:2019-09-13-g1.jpg&amp;diff=2593</id>
		<title>File:2019-09-13-g1.jpg</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=File:2019-09-13-g1.jpg&amp;diff=2593"/>
		<updated>2020-09-03T20:38:35Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Esercizio g1 dell'esame del 2019/09/13.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Esercizio g1 dell'esame del 2019/09/13.&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2592</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2592"/>
		<updated>2020-09-02T15:59:14Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.2 (controllato) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
        altri operai in attesa.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 16:03, 2 September 2020 (CEST). Ritengo sia: corretto&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (controllato) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
&lt;br /&gt;
        if (message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(), dummy) # self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
&lt;br /&gt;
        if (message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (controllato) ===&lt;br /&gt;
* Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 19:13, 1 September 2020 (CEST). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il programma è composto da due processi, ognuno dei quali stampa all'infinito il proprio identificatore. Perché sia possibile stampare è però necessario attendere il proprio turno, condizione gestita dal monitor bohm: esso possiede due stati (0 o 1) ed è possibile entrarvi quando l'id del processo invocante e il valore dello stato corrispondono; la procedura post() di bohm setta lo stato al valore complementare e sveglia il processo in attesa sulla coda di condizione corrispondente (al nuovo stato). &lt;br /&gt;
&lt;br /&gt;
È possibile implementare il meccanismo di sincronizzazione con semafori tramite il codice seguente&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
binary_sempahore[2] sem = {new binary_semaphore(1), new binary_semaphore(0)};&lt;br /&gt;
&lt;br /&gt;
void pre (int n) {&lt;br /&gt;
    sem[n].P();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void post (int n) {&lt;br /&gt;
    sem[1 - n].V();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2591</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2591"/>
		<updated>2020-09-02T14:03:00Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Verificato es c.1 esame 14/02/2019&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
        altri operai in attesa.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf Testo d'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 16:03, 2 September 2020 (CEST). Ritengo sia: corretto&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (controllato) ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (controllato) ===&lt;br /&gt;
* Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 19:13, 1 September 2020 (CEST). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il programma è composto da due processi, ognuno dei quali stampa all'infinito il proprio identificatore. Perché sia possibile stampare è però necessario attendere il proprio turno, condizione gestita dal monitor bohm: esso possiede due stati (0 o 1) ed è possibile entrarvi quando l'id del processo invocante e il valore dello stato corrispondono; la procedura post() di bohm setta lo stato al valore complementare e sveglia il processo in attesa sulla coda di condizione corrispondente (al nuovo stato). &lt;br /&gt;
&lt;br /&gt;
È possibile implementare il meccanismo di sincronizzazione con semafori tramite il codice seguente&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
binary_sempahore[2] sem = {new binary_semaphore(1), new binary_semaphore(0)};&lt;br /&gt;
&lt;br /&gt;
void pre (int n) {&lt;br /&gt;
    sem[n].P();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void post (int n) {&lt;br /&gt;
    sem[1 - n].V();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2590</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2590"/>
		<updated>2020-09-01T17:35:19Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Svolto es c.2 dell'esame 13/09/2019&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
        altri operai in attesa.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (controllato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (controllato) ===&lt;br /&gt;
* Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 19:13, 1 September 2020 (CEST). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il programma è composto da due processi, ognuno dei quali stampa all'infinito il proprio identificatore. Perché sia possibile stampare è però necessario attendere il proprio turno, condizione gestita dal monitor bohm: esso possiede due stati (0 o 1) ed è possibile entrarvi quando l'id del processo invocante e il valore dello stato corrispondono; la procedura post() di bohm setta lo stato al valore complementare e sveglia il processo in attesa sulla coda di condizione corrispondente (al nuovo stato). &lt;br /&gt;
&lt;br /&gt;
È possibile implementare il meccanismo di sincronizzazione con semafori tramite il codice seguente&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
binary_sempahore[2] sem = {new binary_semaphore(1), new binary_semaphore(0)};&lt;br /&gt;
&lt;br /&gt;
void pre (int n) {&lt;br /&gt;
    sem[n].P();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void post (int n) {&lt;br /&gt;
    sem[1 - n].V();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2589</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2589"/>
		<updated>2020-09-01T17:13:55Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.1 (controllato) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
        altri operai in attesa.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (controllato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (controllato) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 19:13, 1 September 2020 (CEST). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2588</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2588"/>
		<updated>2020-09-01T17:13:37Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.1 (controllato) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
        altri operai in attesa.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (controllato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (controllato) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 19:13, 1 September 2020 (CEST). &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2587</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2587"/>
		<updated>2020-09-01T15:47:11Z</updated>

		<summary type="html">&lt;p&gt;Acsor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
        altri operai in attesa.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (controllato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 (controllato) ===&lt;br /&gt;
Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2586</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2586"/>
		<updated>2020-09-01T11:08:24Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
        altri operai in attesa.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (possibile soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2585</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2585"/>
		<updated>2020-09-01T11:05:19Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.1 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
    altri operai in attesa.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (possibile soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Talk:Prove_svolte_e_soluzioni_proposte&amp;diff=2584</id>
		<title>Talk:Prove svolte e soluzioni proposte</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Talk:Prove_svolte_e_soluzioni_proposte&amp;diff=2584"/>
		<updated>2020-08-30T08:20:28Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Replaced content with &amp;quot;= Discussioni =&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Discussioni =&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2583</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=2583"/>
		<updated>2020-08-30T08:17:07Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Spezzettata la pagina &amp;quot;Prove svolte e soluzioni proposte&amp;quot; in più sottopagine&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina raccoglie prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review. Chiunque prenda visione di un esercizio è pregato (per il bene collettivo) a lasciare una [https://www.mediawiki.org/wiki/Help:Signatures propria firma] con nome utente e data di visualizzazione indicando se lo svolgimento è ritenuto corretto; in caso di svolgimento scorretto è invece invitato ad apportare una correzione, lasciando come nel caso precedente il proprio nome utente e data di correzione.&lt;br /&gt;
&lt;br /&gt;
Al fine di verificare la correttezza degli esercizi di concorrenza, segnaliamo la presenza di [[Tool_per_semafori_e_monitor|strumenti di programmazione concorrente]] per i linguaggi C e Python.&lt;br /&gt;
&lt;br /&gt;
== Prove scritte ==&lt;br /&gt;
* [[Prove scritte 2019]]&lt;br /&gt;
* [[Prove scritte 2018]]&lt;br /&gt;
* [[Prove scritte 2017]]&lt;br /&gt;
* [[Prove scritte 2015]]&lt;br /&gt;
* [[Prove scritte 2014]]&lt;br /&gt;
* [[Prove scritte 2011]]&lt;br /&gt;
* [[Prove scritte 2005]]&lt;br /&gt;
&lt;br /&gt;
== Prove pratiche ==&lt;br /&gt;
* [[Prove pratiche 2018]]&lt;br /&gt;
* [[Prove pratiche 2016]]&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_pratiche_2018&amp;diff=2582</id>
		<title>Prove pratiche 2018</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_pratiche_2018&amp;diff=2582"/>
		<updated>2020-08-30T08:15:40Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Created page with &amp;quot;== Esame Pratico 21/09/2018 == http://www.cs.unibo.it/~renzo/so/pratiche/2018.09.21.pdf === Esercizio 1 === &amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;        #define _GNU_SOURCE        #include &amp;lt;sys/s...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_pratiche_2016&amp;diff=2581</id>
		<title>Prove pratiche 2016</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_pratiche_2016&amp;diff=2581"/>
		<updated>2020-08-30T08:14:09Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Created page with &amp;quot; == Esame Pratico 22/01/2016 == http://www.cs.unibo.it/~renzo/so/pratiche/2016.01.22.pdf === Esercizio 1 === &amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt; #include &amp;lt;stdlib.h&amp;gt; #include &amp;lt;stdio.h&amp;gt; #include ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Esame Pratico 22/01/2016 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2016.01.22.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dirent.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef struct nameNumber {&lt;br /&gt;
        char *name;&lt;br /&gt;
        int value;&lt;br /&gt;
} nameNumber;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int prefixToInt (char *string) {&lt;br /&gt;
    int i = 0;&lt;br /&gt;
    int num = 0;&lt;br /&gt;
&lt;br /&gt;
    while (string[i] &amp;gt;= '0' &amp;amp;&amp;amp; string[i] &amp;lt; '9' &amp;amp;&amp;amp; i &amp;lt; strlen(string)) {&lt;br /&gt;
        num = (num*10) + (string[i]-'0');&lt;br /&gt;
        i++;&lt;br /&gt;
    }&lt;br /&gt;
    return num;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void fileSort(struct nameNumber **files) {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int comp (const void * el1, const void * el2) {&lt;br /&gt;
    struct nameNumber *f = *((nameNumber**)el1);&lt;br /&gt;
    struct nameNumber *s = *((nameNumber**)el2);&lt;br /&gt;
    if (f-&amp;gt;value &amp;gt; s-&amp;gt;value) return 1;&lt;br /&gt;
    if (f-&amp;gt;value &amp;lt; s-&amp;gt;value) return -1;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int arg, char* argv[]) {&lt;br /&gt;
    struct nameNumber **files;&lt;br /&gt;
&lt;br /&gt;
    DIR *dir;&lt;br /&gt;
    struct dirent *ent;&lt;br /&gt;
&lt;br /&gt;
    int count = 0;&lt;br /&gt;
&lt;br /&gt;
    if((dir = opendir(argv[1])) != NULL) &lt;br /&gt;
    {&lt;br /&gt;
        while( (ent = readdir(dir)) != NULL ) &lt;br /&gt;
        {   &lt;br /&gt;
            if (ent-&amp;gt;d_name[0] &amp;lt; '9' &amp;amp;&amp;amp; ent-&amp;gt;d_name[0] &amp;gt;= '0') &lt;br /&gt;
            {&lt;br /&gt;
                files = (struct nameNumber**)realloc(files , (count+1) * sizeof(struct nameNumber*));&lt;br /&gt;
                files[count] = (struct nameNumber*)malloc(sizeof(struct nameNumber));&lt;br /&gt;
                files[count]-&amp;gt;name = (char*)malloc(sizeof(char)*strlen(ent-&amp;gt;d_name) + 1);&lt;br /&gt;
                strcpy(files[count]-&amp;gt;name, ent-&amp;gt;d_name);&lt;br /&gt;
                files[count]-&amp;gt;value = prefixToInt(files[count]-&amp;gt;name);&lt;br /&gt;
                printf(&amp;quot;name : %s  ,  value : %d\n&amp;quot;, files[count]-&amp;gt;name , files[count]-&amp;gt;value);&lt;br /&gt;
                count++;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    qsort(files, count, sizeof(nameNumber*), comp);&lt;br /&gt;
&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i=0; i &amp;lt; count; i++) {&lt;br /&gt;
        printf(&amp;quot;%s\n&amp;quot;,files[i]-&amp;gt;name);&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>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2005&amp;diff=2580</id>
		<title>Prove scritte 2005</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2005&amp;diff=2580"/>
		<updated>2020-08-30T08:12:04Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Created page with &amp;quot;== Esame di Concorrenza del 13/01/2005 == Il testo degli esercizi è disponibile alla pagina http://www.cs.unibo.it/~renzo/so/compiti/2005-01-13.con.pdf.  === Esercizio 1 (da ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame di Concorrenza del 13/01/2005 ==&lt;br /&gt;
Il testo degli esercizi è disponibile alla pagina http://www.cs.unibo.it/~renzo/so/compiti/2005-01-13.con.pdf.&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 1 (da controllare) ===&lt;br /&gt;
Il codice di questo esercizio può essere eseguito scaricando il sorgente Python e l'archivio relativo agli [[Tool_per_semafori_e_monitor|strumenti di concorrenza per il linguaggio Python]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
import threading&lt;br /&gt;
import random&lt;br /&gt;
import time&lt;br /&gt;
from pysm.semaphore import semaphore&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class mod_counter:&lt;br /&gt;
    def __init__(self, mod, start=0):&lt;br /&gt;
        self._mod = mod&lt;br /&gt;
        self._val = start&lt;br /&gt;
&lt;br /&gt;
    def inc(self):&lt;br /&gt;
        self._val = (self._val + 1) % self._mod&lt;br /&gt;
&lt;br /&gt;
    def get(self):&lt;br /&gt;
        return self._val&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class process(threading.Thread):&lt;br /&gt;
    def __init__(self, to_print, c: mod_counter, a, t, r):&lt;br /&gt;
        threading.Thread.__init__(self, name=&amp;quot;proc&amp;quot; + to_print)&lt;br /&gt;
&lt;br /&gt;
        if to_print not in &amp;quot;tar&amp;quot;:&lt;br /&gt;
            raise ValueError(&amp;quot;Unexpected printable character:&amp;quot;, to_print)&lt;br /&gt;
&lt;br /&gt;
        self._counter = c&lt;br /&gt;
        self._x = to_print&lt;br /&gt;
        self._semaphores = {'t': t, 'a': a, 'r': r}&lt;br /&gt;
        self._enter = True&lt;br /&gt;
&lt;br /&gt;
        if self._x == 't':&lt;br /&gt;
            self._semaphores[self._x].V()&lt;br /&gt;
&lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            self.sync()&lt;br /&gt;
            print(&amp;quot;[%s] %c&amp;quot; % (self.name, self._x))&lt;br /&gt;
&lt;br /&gt;
            # Print a trailing newline&lt;br /&gt;
            if (self._counter.get() == 7):&lt;br /&gt;
                print()&lt;br /&gt;
&lt;br /&gt;
            time.sleep(random.random() * 0.5)&lt;br /&gt;
&lt;br /&gt;
    def sync(self):&lt;br /&gt;
        if (self._enter):&lt;br /&gt;
            self._semaphores[self._x].P()&lt;br /&gt;
            self._enter = False&lt;br /&gt;
        else:&lt;br /&gt;
            self._counter.inc()&lt;br /&gt;
            curr = &amp;quot;taratata&amp;quot;[self._counter.get()]&lt;br /&gt;
&lt;br /&gt;
            self._semaphores[curr].V()&lt;br /&gt;
&lt;br /&gt;
            self._enter = True&lt;br /&gt;
            self.sync()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    counter = mod_counter(8)&lt;br /&gt;
    semaphores = (semaphore(0), semaphore(0), semaphore(0))&lt;br /&gt;
    procs = [process(c, counter, *semaphores) for c in &amp;quot;tar&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.daemon = True&lt;br /&gt;
        p.start()&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2011&amp;diff=2579</id>
		<title>Prove scritte 2011</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2011&amp;diff=2579"/>
		<updated>2020-08-30T08:08:55Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Created page with &amp;quot;== Esame 11/05/2011 == [http://www.cs.unibo.it/~renzo/so/compiti/2011-05-11.con.pdf 2011-05-11.con.pdf] === Esercizio 2 (da controllare) === &amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt; stack s; semapho...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2578</id>
		<title>Prove scritte 2014</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2014&amp;diff=2578"/>
		<updated>2020-08-30T08:07:17Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Created page with &amp;quot;== Esame 16/07/2014 == [http://www.cs.unibo.it/~renzo/so/compiti/2014.07.16.tot.pdf 2014.07.16.tot.pdf] === Esercizio c.1 === &amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt; /* Monitor Bounded Buffer: (non...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2015&amp;diff=2577</id>
		<title>Prove scritte 2015</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2015&amp;diff=2577"/>
		<updated>2020-08-30T08:05:53Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Created page with &amp;quot;== Esame 14/02/2015 == [http://www.cs.unibo.it/~renzo/so/compiti/2015.02.14.tot.pdf 2015.02.14.tot.pdf] === Esercizio c.1 (da controllare) === &amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt; monitor altcol...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
monitor altcolbb {&lt;br /&gt;
&lt;br /&gt;
  generic_type valueBuf[MAX];&lt;br /&gt;
  int front = rear = 0;&lt;br /&gt;
&lt;br /&gt;
  bool isFull = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write[2]; //gli indici sono i colori (red=0, blue=1)&lt;br /&gt;
&lt;br /&gt;
  lastColor = None;&lt;br /&gt;
&lt;br /&gt;
  entry void write(color_t color, generic_type val) {&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
        if(isFull)&lt;br /&gt;
          ok2write[color].wait();&lt;br /&gt;
    else&lt;br /&gt;
      if (lastColor == color)&lt;br /&gt;
        ok2write[color].wait();&lt;br /&gt;
              &lt;br /&gt;
    valueBuf[front] = val;&lt;br /&gt;
    front = (front+1) % MAX;&lt;br /&gt;
    lastColor = color;&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
      isFull = true;&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-color].signal();&lt;br /&gt;
&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
        &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry generic_type read(void) {&lt;br /&gt;
&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      if (!isFull)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
&lt;br /&gt;
    generic_type tmpValue = valueBuf[rear];&lt;br /&gt;
    &lt;br /&gt;
    rear = (rear + 1) % MAX;&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      isFull = false;&lt;br /&gt;
      color_t tmpColor = lastColor;&lt;br /&gt;
      lastColor = None;&lt;br /&gt;
      ok2write[tmpColor].signal();  //quando un lettore legge l'ultimo elemento&lt;br /&gt;
                                    //dal buffer, ci possono solo essere scrittori&lt;br /&gt;
                                    //in attesa che abbiano lo stesso colore&lt;br /&gt;
                                    //dell'ultimo elemento.&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-lastColor].signal();&lt;br /&gt;
      &lt;br /&gt;
    return tmpValue;&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;
&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 c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
Il programma dispone di una mutex per l'accesso protetto alla variabile n, e dei due semafori s1 ed s2 per regolare l'alternanza tra i thread A e AB. Sulla base di essi, e del fatto che entrambi i thread eseguono 2 cicli, è possibile affermare (verificare) che&lt;br /&gt;
&lt;br /&gt;
* L'alternanza dei due thread è A-AB-A-AB o&lt;br /&gt;
* L'alternanza dei due thread è AB-A-AB-A&lt;br /&gt;
&lt;br /&gt;
Infatti se il thread A svolgesse due cicli consecutivamente, invocherebbe s1.P() due volte senza fare mai ricorso a s1.V() (ragionamento analogo per AB); pertanto è necessario attendere l'intervento dell'altro thread in attesa di una chiamata su s1.V().&lt;br /&gt;
&lt;br /&gt;
Per concludere, i possibili valori di n al termine del programma saranno, in corrispondenza delle due diramazioni elencate sopra&lt;br /&gt;
&lt;br /&gt;
* n = 12&lt;br /&gt;
* n = 5&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente [[User:Acsor|Acsor]] in data 23/08/2020. Ritengo sia: corretto&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&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;
==== Punto b) ====&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;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
# Frammentazione interna: allocazioni di pagine la cui dimensione è strettamente maggiore di quella effettivamente richiesta.  Frammentazione esterna: nessuno. Infatti ogni spazio (pagina) allocato e liberato è prima o poi riallocato.&lt;br /&gt;
# Se non viene utilizzato un sistema di caching, una lettura diretta a più blocchi di un file di grandi dimensioni richiede: la lettura della FAT, solitamente posta all'inizio di un [[Glossario#Volume|volume]] (e dunque, su dischi rotazionali, in una traccia differente da quella attuale o da quella del blocco da leggere); la lettura del blocco stesso, e dunque lo spostamento della testina nella traccia e nel settore di interesse&lt;br /&gt;
# Uno scheduling a priorità statica può essere utile ad un processo interattivo, dove è necessario mantenersi all'interno di date soglie temporali o semplicemente svolgere un dato compito con meno ritardo possibile; esempi concreti: un processo che faccia streaming video; un processo appartenente ad un server il cui obiettivo primario è soddisfare le richieste dei propri client il prima possibile, ma dove può anche essere svolta qualche attività dai processi locali (es. programmi applicativi). In uno scheduling a priorità statica, se la presenza di processi ad alte priorità è costante, possono verificarsi indesiderati fenomeni di ''starvation'' nei confronti di processi meno prioritari.&lt;br /&gt;
# ''Domanda puramente nozionistica, la cui risposta può essere ricavata consultando note, lucidi o libri di testo.''&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&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;
    if (buffer.lenght() &amp;gt;= MAX) {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX) {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&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;
    generic_type val;&lt;br /&gt;
&lt;br /&gt;
    if (buffer.lenght() == 0) {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&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;
&lt;br /&gt;
    val = buffer.length() == 0 ? NULL: buffer.dequeue();&lt;br /&gt;
    ok2write.signal();&lt;br /&gt;
&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 ===&lt;br /&gt;
&lt;br /&gt;
* Controllato e corretto dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&lt;br /&gt;
===== Algoritmo MIN =====&lt;br /&gt;
&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;
===== Algoritmo 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;
==== Punto b) ====&lt;br /&gt;
&lt;br /&gt;
Poiché non è specificato quale dei due algoritmi precedenti applicare, sono state considerate soluzioni per ognuno di essi&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo MIN (da controllare) =====&lt;br /&gt;
(È possibile ottenere una stringa più breve?)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
4 3 2 1 5 3 2 1 4 5 3 2 1 3 2 4 5 1 2 4 3 1 5 4 2 1 3 4   &lt;br /&gt;
-------------------------------------------------------&lt;br /&gt;
4|4|4|4|5|  5  |5|  5  |1|  1  |1|  1  |1|  1  |   1   &lt;br /&gt;
 |3|3|3|3|  3  |3|  3  |3|  3  |5|  5  |5|  5  |   2   &lt;br /&gt;
 | |2|2|2|  2  |2|  2  |2|  2  |2|  2  |3|  3  |   3   &lt;br /&gt;
 | | |1|1|  1  |4|  4  |4|  4  |4|  4  |4|  4  |   4   &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo LRU =====&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 1 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 4 4 4 4 4 4 4&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2017&amp;diff=2576</id>
		<title>Prove scritte 2017</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2017&amp;diff=2576"/>
		<updated>2020-08-30T08:03:50Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Created page with &amp;quot;== Esame 11/09/2017 == [http://www.cs.unibo.it/~renzo/so/compiti/2017.09.11.tot.pdf 2017.09.11.tot.pdf] === Esercizio c.1 === &amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt; monitor crossing  ok2dir[4];   ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&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;
        entry 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;
        entry 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;
        entry 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;
&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;
si, è possibile: &lt;br /&gt;
&lt;br /&gt;
Implementare asend e arecv date bsend e brecv&lt;br /&gt;
&lt;br /&gt;
asend(pid_t, msg_type msg){&lt;br /&gt;
    bsend (&amp;lt;pid_t dst, msg&amp;gt;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
arecv(*){&lt;br /&gt;
  pid_t act = getpid(); \\ act = proprio pid &lt;br /&gt;
  do{&lt;br /&gt;
    &amp;lt;dst, msg&amp;gt; = brecv(*);&lt;br /&gt;
  }while (dst =! act)&lt;br /&gt;
  return msg;&lt;br /&gt;
}&lt;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;
entry 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;
entry 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;
entry 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;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2018&amp;diff=2575</id>
		<title>Prove scritte 2018</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2018&amp;diff=2575"/>
		<updated>2020-08-30T08:02:00Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Created page with &amp;quot;== Esame 19/09/2018 == [http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf Testo dell'esame].  === Esercizio c.2 (da controllare) ===  * Controllato dall'utente ? in ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf Testo dell'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Nello pseudocodice seguente, il termine this fa riferimento al processo corrente, mentre ANY ad uno qualunque.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack&amp;lt;message&amp;gt; messages;&lt;br /&gt;
&lt;br /&gt;
void lifo_send(string m, process dest) {&lt;br /&gt;
	do {&lt;br /&gt;
		asend(m, dest);&lt;br /&gt;
	} while (areceive(dest).text != &amp;quot;ACK&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
message lifo_receive(process source) {&lt;br /&gt;
	if (source != ANY) {&lt;br /&gt;
		message m = areceive(source);&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;ACK&amp;quot;, source);&lt;br /&gt;
&lt;br /&gt;
		return m;&lt;br /&gt;
	} else {&lt;br /&gt;
		message m;&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;END&amp;quot;, this);&lt;br /&gt;
		m = areceive(ANY);&lt;br /&gt;
&lt;br /&gt;
		while (m.text != &amp;quot;END&amp;quot; || m.sender != this) {&lt;br /&gt;
			messages.push(m);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                /* Bisogna tenere conto dei casi in cui lifo_receive() viene invocata quando nessun&lt;br /&gt;
                 * messaggio è stato ancora spedito da altri processi. In tal caso si attende il&lt;br /&gt;
                 * il primo e lo si restituisce.&lt;br /&gt;
                 */&lt;br /&gt;
		if (messages.empty()) {&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			return m;&lt;br /&gt;
		} else {&lt;br /&gt;
			return messages.pop();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&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;
* Visto e corretto dall'utente [[User:Acsor|Acsor]] in data 23/08/2020&lt;br /&gt;
* Visto e corretto dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
class LIFOBuffer {&lt;br /&gt;
	stack&amp;lt;T&amp;gt; s;&lt;br /&gt;
	semaphore mutex(1); // mutua esclusione&lt;br /&gt;
	semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
	void push (T value) {&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		s.push(value);&lt;br /&gt;
                // (1)&lt;br /&gt;
		mutex.V()&lt;br /&gt;
&lt;br /&gt;
		ok2consume.V()  // Curiosità: che succede se spostiamo quest'istruzione in (1)?&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	T pop () {&lt;br /&gt;
		T value;&lt;br /&gt;
&lt;br /&gt;
		ok2consume.P();&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		value = s.pop();&lt;br /&gt;
		mutex.V();&lt;br /&gt;
&lt;br /&gt;
		return value;&lt;br /&gt;
	}&lt;br /&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;
# In sistemi dove dispositivi di archiviazione o supporti hardware per la memoria virtuale (e dunque per la paginazione, spesso utilizzata per realizzare il supporto di memoria virtuale) non sono presenti (es. sistemi embedded). ''(In sistemi real-time la memoria virtuale è praticabile? Annotare.)''&lt;br /&gt;
# 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.&lt;br /&gt;
# Per fornire parallelismo e ridondanza. Non è necessario fare backup dei dati sul disco, nel senso di mantenere una copia identica di dati già memorizzati altrove, in quanto diversi sistemi di codici permettono il rilevamento e/o la correzione di errori.&lt;br /&gt;
# Se in un grafo di Holt multirisorsa esiste un ciclo tra più processi e risorse, ciò non significa che allo stesso tempo non siano coinvolti processi con archi esclusivamente entranti. Ogni processo appartenente a questa categoria non è in attesa di risorse, e può dunque procedere con i suoi calcoli; quando avrà terminato rilascerà le risorse precedentemente allocategli, eventualmente sbloccando uno dei processi coinvolti nel ciclo.&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;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
proc[x]: x='a',...,'z'&lt;br /&gt;
 while True:&lt;br /&gt;
  //c sarà il carattere stampato dal processo precedente&lt;br /&gt;
  (c, string) = arecv(*)&lt;br /&gt;
  if(string == wait){&lt;br /&gt;
    //mi metto in attesa di ricevere l'ACK da proc[x]&lt;br /&gt;
    m=arecv(x);&lt;br /&gt;
  }&lt;br /&gt;
  if (c == NONE){&lt;br /&gt;
    //significa che sei il primo a ricevere quella stringa&lt;br /&gt;
    print(x);&lt;br /&gt;
    if (len(string) &amp;gt; 1){&lt;br /&gt;
      //mando la wait a tutti, il primo che riceve qualcosa da stampare manda una wait a tutti&lt;br /&gt;
      asend(wait,*);&lt;br /&gt;
      int l = len(string);&lt;br /&gt;
      int i = 1;&lt;br /&gt;
      while(l != 0){&lt;br /&gt;
        asend(proc[string[i]], (x, string[i...]));&lt;br /&gt;
        //si mette in attesa di ricevere l'ACK dal processo dell'ultima lettera della parola&lt;br /&gt;
        m=areceive(proc[string[i]]);&lt;br /&gt;
        //rimando la wait al processo per ribloccarlo&lt;br /&gt;
        asend(wait, proc[string[i]])&lt;br /&gt;
        l--;&lt;br /&gt;
        i++;&lt;br /&gt;
      }&lt;br /&gt;
      //dopo aver finito la stampa della stringa sblocco tutti i processi&lt;br /&gt;
      asend(ACK, *);&lt;br /&gt;
    }&lt;br /&gt;
  }else{&lt;br /&gt;
    print(x);&lt;br /&gt;
    asend(ACK, x);&lt;br /&gt;
    //ricomincia il ciclo while, si rimette in attesa e il 'gestore gli rimanda la wait'&lt;br /&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;
&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;
&lt;br /&gt;
monitor bridge:&lt;br /&gt;
&lt;br /&gt;
    int ncar&lt;br /&gt;
    bool boat_on_0&lt;br /&gt;
    bool boat_on_1       // per semplicità, quando nel codice si trova boat_on_(direction) oppure isBoat(direction)(),&lt;br /&gt;
                         // si valuta il valore booleano di direction e lo si applica sotto forma di stringa al simbolo&lt;br /&gt;
                         // ad esso adiacente&lt;br /&gt;
    bool is_raised&lt;br /&gt;
    queue waiting_mean   // i valori possibili sono: boat0, boat1 oppure car&lt;br /&gt;
    condition ok2go&lt;br /&gt;
  &lt;br /&gt;
    entry car_enter(direction): &lt;br /&gt;
        if is_raised || ncar == MAXCAR:&lt;br /&gt;
            waiting_mean.enqueue(car)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        is_raised = false&lt;br /&gt;
        ++ncar&lt;br /&gt;
  &lt;br /&gt;
    entry car_exit(direction):&lt;br /&gt;
        --ncar&lt;br /&gt;
        if (waiting_mean.top().isBoat() &amp;amp;&amp;amp; ncar == 0) || waiting_mean.top().isCar():    // isBoat ritorna true se l'oggetto su cui&lt;br /&gt;
            waiting_mean.dequeue()                                                      // è invocata è boat0 oppure boat1&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
  &lt;br /&gt;
    entry boat_enter(direction):&lt;br /&gt;
        if !is_raised || boat_on_(direction):&lt;br /&gt;
            waiting_mean.enqueue(boat)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        if waiting_mean.top().isBoat(!direction)():&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
        is_raised = true&lt;br /&gt;
        boat_on_(direction) = true&lt;br /&gt;
  &lt;br /&gt;
    entry boat_exit(direction):&lt;br /&gt;
        boat_on_(direction) = false&lt;br /&gt;
        if !boat_on_(!direction):&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
&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;
=== 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;
entry 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;
entry 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;
entry 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;
entry 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 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge {&lt;br /&gt;
&lt;br /&gt;
  UP=0;&lt;br /&gt;
  DOWN=1;&lt;br /&gt;
  bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
  bool carAreExiting = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2drive;&lt;br /&gt;
  condition ok2barca[2];&lt;br /&gt;
&lt;br /&gt;
  waitingCar = 0;&lt;br /&gt;
  carOnBridge = 0;&lt;br /&gt;
&lt;br /&gt;
  boatWaiting[2] = {0,0};&lt;br /&gt;
  boatIsPassing[2] = {false,false}&lt;br /&gt;
&lt;br /&gt;
  entry car_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == DOWN)&lt;br /&gt;
      if(carOnBridge == MAXCAR)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
      else if (carAreExiting)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
    else &lt;br /&gt;
      if (boatIsPassing[0] || boatIsPassing[1])&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
    carOnBridge++;&lt;br /&gt;
    carAreExiting = false;&lt;br /&gt;
    if(carOnBridge &amp;lt; MAXCAR &amp;amp;&amp;amp; !carAreExiting) &lt;br /&gt;
      ok2drive.signal();&lt;br /&gt;
      &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry car_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    carOnBridge--;&lt;br /&gt;
    carAreExiting = true;&lt;br /&gt;
&lt;br /&gt;
    if(carOnBridge == 0)&lt;br /&gt;
      carAreExiting = false;&lt;br /&gt;
      if(boatWaiting[0] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[0].signal();&lt;br /&gt;
      else if (boatWaiting[1] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[1].signal();&lt;br /&gt;
      else &lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == UP)&lt;br /&gt;
    | if (boatIsPassing[direction] == true)&lt;br /&gt;
    | |  boatWaiting[direction]++;&lt;br /&gt;
    | |  ok2barca.wait();&lt;br /&gt;
    | |  boatWaiting[direction]--;&lt;br /&gt;
    else &lt;br /&gt;
    | if (carOnBridge &amp;gt; 0)&lt;br /&gt;
    | | boatWaiting[direction]++;&lt;br /&gt;
    | | ok2barca.wait();&lt;br /&gt;
    | | boatWaiting[direction]--;&lt;br /&gt;
    | | bridgeis = UP;&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = true;&lt;br /&gt;
&lt;br /&gt;
    if(boatIsPassing[1-direction] == false &amp;amp;&amp;amp; boatWaiting[1-direction] &amp;gt; 0)&lt;br /&gt;
      ok2barca[1-direction].signal();&lt;br /&gt;
    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = false;&lt;br /&gt;
&lt;br /&gt;
    if (boatIsPassing[1-direction] == false)&lt;br /&gt;
      if (waitingCar &amp;gt; 0)&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
    else&lt;br /&gt;
        if (waitingCar == 0)&lt;br /&gt;
          ok2barca[direction].signal();&lt;br /&gt;
          &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&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;
entry 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;
entry 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;
entry 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;
entry 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;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
# (Ri)Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 26/08/2020&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
list printed_msg;  # questa è una variabile condivisa che ai fini dell'esercizio non si può utilizzare (message passing)&lt;br /&gt;
&lt;br /&gt;
process server[i]:&lt;br /&gt;
  while true:&lt;br /&gt;
    &amp;lt;msg, pid&amp;gt; = arecv(*)&lt;br /&gt;
&lt;br /&gt;
    if printed_msg.length == 0 or &amp;lt;msg, pid&amp;gt; is not in printed_msg:&lt;br /&gt;
      printed_msg.append(&amp;lt;msg,id&amp;gt;)&lt;br /&gt;
      print(msg)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
Nello svolgimento seguente, receiver incapsula l'ambiente privato del processo; _peers rappresenta il vettore di processi &amp;quot;fratelli&amp;quot; ai quali può essere chiesto di stampare un messaggio, mentre _printed contiene l'hash di tutti i messaggi stampati dal processo locale. Si suppone che istanze della classe receiver possano essere passate come parametro ad areceive() ed asend() (non implementate).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class receiver:&lt;br /&gt;
    def __init__(self, peers):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param peers: list of processes this process communicates with.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self._peers = tuple(peers)&lt;br /&gt;
        self._printed = list()&lt;br /&gt;
    &lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            process, message = areceive(ANY)&lt;br /&gt;
&lt;br /&gt;
            if process in self._peers:&lt;br /&gt;
                self._reply_query(process, message)&lt;br /&gt;
            else:&lt;br /&gt;
                self._print(process, message)&lt;br /&gt;
&lt;br /&gt;
    def _print(self, sender, message):&lt;br /&gt;
        h = hash(message.text)&lt;br /&gt;
&lt;br /&gt;
        if h not in self._printed and not self._printed_from_peers(message):&lt;br /&gt;
            self._printed.append(h)&lt;br /&gt;
            print(message.text)&lt;br /&gt;
&lt;br /&gt;
    def _reply_query(self, sender, h):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Invoked when the current process receive a &amp;quot;query&amp;quot; from a peer process.&lt;br /&gt;
        `h` contains the hash of a message which may or may have not been&lt;br /&gt;
        sent from this process; if it was sent, the reply is `Yes`, otherwise `No`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        reply = &amp;quot;Yes&amp;quot; if int(h) in self._printed else &amp;quot;No&amp;quot;&lt;br /&gt;
        asend(sender, reply)&lt;br /&gt;
&lt;br /&gt;
    def _printed_from_peers(self, message):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `True` if this message has already been printed from any of the&lt;br /&gt;
        peer processes, `False` otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        h = hash(message)&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            asend(p, str(h))&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            _, reply = areceive(p)&lt;br /&gt;
&lt;br /&gt;
            if reply.text == &amp;quot;Yes&amp;quot;:&lt;br /&gt;
                return True&lt;br /&gt;
            else if reply.text != &amp;quot;No&amp;quot;:&lt;br /&gt;
                # If the response is neither &amp;quot;Yes&amp;quot; nor &amp;quot;No&amp;quot;, then we have got a query&lt;br /&gt;
                self._reply_query(p, reply)&lt;br /&gt;
&lt;br /&gt;
        return False&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Sulla base dei valori in entrata, è possibile costruire le matrici Allocation (q.tà di risorse allocate per processo e per tipo), Need (q.tà di risorse che ogni processo potrebbe ancora chiedere) e il vettore Available (num. di risorse correntemente disponibili).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left&amp;quot;&lt;br /&gt;
! colspan=3 | Allocation&lt;br /&gt;
|-&lt;br /&gt;
   !   !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 4 || 5&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 3 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 2 || 4&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=3 | Need&lt;br /&gt;
|-&lt;br /&gt;
   !    !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 6 || 8&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 6 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 6 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=2 | Available&lt;br /&gt;
|-&lt;br /&gt;
   ! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | x || y&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nel caso delle risorse di tipo A, deve aversi x &amp;gt;= 6 in quanto un processo dovrà essere selezionato come primo nella permutazione dell'algoritmo del banchiere multivaluta, e tutti quelli correnti hanno lo stesso valore Need(i)(1); per ciò che riguarda le risorse di tipo B, possiamo ragionare per esaustione&lt;br /&gt;
&lt;br /&gt;
* Se il primo processo della permutazione è p1, allora y &amp;gt;= 8 (con questo valore posso soddisfare la richiesta di p1 e in seguito tutte le altre)&lt;br /&gt;
* Se il primo processo della permutazione è p2, allora y &amp;gt;= 5: con questo valore è possibile soddisfare la richiesta di p2; una volta che esso avrà finito, restituirà 3 unità della risorsa B, che permetteranno di soddisfare sia le richieste di A sia quelle di C&lt;br /&gt;
* Se il primo processo della permutazione è p3, allora y &amp;gt;= 8 (ragionamento analogo come per p1)&lt;br /&gt;
&lt;br /&gt;
Volendo scegliere il minimo, y &amp;gt;= 5, ed in conclusione (x, y) &amp;gt;= (6, 5).&lt;br /&gt;
&lt;br /&gt;
''Svolgimento basato in parte sull'approccio di Operating System Concepts di Silberschatz. et al, 9th edition, cap. 7.''&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# Può accadere che il sistema torni in uno stato di safety o che invece porti a deadlock. Diversamente uno stato di safety non può portare direttamente ad uno stato di deadlock, ma solo ad uno di non-safety.&lt;br /&gt;
# Selezionare uno o più tra i processi attivi e sospenderli, salvando il loro stato su memoria secondaria operando delle operazioni di swap-out, finché l'insieme dei frame nella memoria centrale non è in grado di soddisfare tutti i processi rimasti attivi.&lt;br /&gt;
# La scelta è determinata perlopiù dal fattore costo. Con un sistema RAID 1 è possibile ripristinare un disco guasto molto brevemente, in quanto le operazioni coinvolte prevedono una semplice ricopiatura dal disco di backup; con un sistema RAID 5 il ripristino del disco guasto deve coinvolgere tutti i dischi dell'intero array, e ciò può richiedere anche ore per dischi di grandi dimensioni. D'altra parte RAID 1 è più costoso (con n dischi, posso memorizzare tanta informazione quanto potrei con n / 2 dischi) rispetto a RAID 5 dove, tra gli n dischi, complessivamente soltanto uno è destinato alle informazioni di ridondanza.&lt;br /&gt;
# ''Completare.''&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2574</id>
		<title>Prove scritte 2019</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_scritte_2019&amp;diff=2574"/>
		<updated>2020-08-30T07:59:30Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Created page with &amp;quot;== Esame 18/06/2019 == [http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.tot.pdf] === Esercizio c.1 (da controllare) === &amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt; monitor pg{   ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Esame 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente Lusvelt in data 26/08/2020 (sbagliato, dal testo si evince che se manca anche solo un componente bisogna mettersi in attesa finchè non arrivi, per poi prendere anche gli altri).&lt;br /&gt;
:: E non è quel che già accade nel ramo else di get()? C'è una wait() ed essa è invocata proprio quando components[i] &amp;gt; self._v[i]. (La chat in Wiki è scomoda, sentiamoci su Telegram.) -- [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:32, 26 August 2020 (CEST)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
    altri operai in attesa.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (possibile soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2573</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=2573"/>
		<updated>2020-08-28T13:28:05Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esame 19/09/2018 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina raccoglie prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review. Chiunque prenda visione di un esercizio è pregato (per il bene collettivo) a lasciare una [https://www.mediawiki.org/wiki/Help:Signatures propria firma] con nome utente e data di visualizzazione indicando se lo svolgimento è ritenuto corretto; in caso di svolgimento scorretto è invece invitato ad apportare una correzione, lasciando come nel caso precedente il proprio nome utente e data di correzione.&lt;br /&gt;
&lt;br /&gt;
Al fine di verificare la correttezza degli esercizi di concorrenza, segnaliamo la presenza di [[Tool_per_semafori_e_monitor|strumenti di programmazione concorrente]] per i linguaggi C e Python.&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&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 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente Lusvelt in data 26/08/2020 (sbagliato, dal testo si evince che se manca anche solo un componente bisogna mettersi in attesa finchè non arrivi, per poi prendere anche gli altri).&lt;br /&gt;
:: E non è quel che già accade nel ramo else di get()? C'è una wait() ed essa è invocata proprio quando components[i] &amp;gt; self._v[i]. (La chat in Wiki è scomoda, sentiamoci su Telegram.) -- [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:32, 26 August 2020 (CEST)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
    altri operai in attesa.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (possibile soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&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 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf Testo dell'esame].&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Nello pseudocodice seguente, il termine this fa riferimento al processo corrente, mentre ANY ad uno qualunque.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack&amp;lt;message&amp;gt; messages;&lt;br /&gt;
&lt;br /&gt;
void lifo_send(string m, process dest) {&lt;br /&gt;
	do {&lt;br /&gt;
		asend(m, dest);&lt;br /&gt;
	} while (areceive(dest).text != &amp;quot;ACK&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
message lifo_receive(process source) {&lt;br /&gt;
	if (source != ANY) {&lt;br /&gt;
		message m = areceive(source);&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;ACK&amp;quot;, source);&lt;br /&gt;
&lt;br /&gt;
		return m;&lt;br /&gt;
	} else {&lt;br /&gt;
		message m;&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;END&amp;quot;, this);&lt;br /&gt;
		m = areceive(ANY);&lt;br /&gt;
&lt;br /&gt;
		while (m.text != &amp;quot;END&amp;quot; || m.sender != this) {&lt;br /&gt;
			messages.push(m);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                /* Bisogna tenere conto dei casi in cui lifo_receive() viene invocata quando nessun&lt;br /&gt;
                 * messaggio è stato ancora spedito da altri processi. In tal caso si attende il&lt;br /&gt;
                 * il primo e lo si restituisce.&lt;br /&gt;
                 */&lt;br /&gt;
		if (messages.empty()) {&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			return m;&lt;br /&gt;
		} else {&lt;br /&gt;
			return messages.pop();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&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;
* Visto e corretto dall'utente [[User:Acsor|Acsor]] in data 23/08/2020&lt;br /&gt;
* Visto e corretto dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
class LIFOBuffer {&lt;br /&gt;
	stack&amp;lt;T&amp;gt; s;&lt;br /&gt;
	semaphore mutex(1); // mutua esclusione&lt;br /&gt;
	semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
	void push (T value) {&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		s.push(value);&lt;br /&gt;
                // (1)&lt;br /&gt;
		mutex.V()&lt;br /&gt;
&lt;br /&gt;
		ok2consume.V()  // Curiosità: che succede se spostiamo quest'istruzione in (1)?&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	T pop () {&lt;br /&gt;
		T value;&lt;br /&gt;
&lt;br /&gt;
		ok2consume.P();&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		value = s.pop();&lt;br /&gt;
		mutex.V();&lt;br /&gt;
&lt;br /&gt;
		return value;&lt;br /&gt;
	}&lt;br /&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;
# In sistemi dove dispositivi di archiviazione o supporti hardware per la memoria virtuale (e dunque per la paginazione, spesso utilizzata per realizzare il supporto di memoria virtuale) non sono presenti (es. sistemi embedded). ''(In sistemi real-time la memoria virtuale è praticabile? Annotare.)''&lt;br /&gt;
# 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.&lt;br /&gt;
# Per fornire parallelismo e ridondanza. Non è necessario fare backup dei dati sul disco, nel senso di mantenere una copia identica di dati già memorizzati altrove, in quanto diversi sistemi di codici permettono il rilevamento e/o la correzione di errori.&lt;br /&gt;
# Se in un grafo di Holt multirisorsa esiste un ciclo tra più processi e risorse, ciò non significa che allo stesso tempo non siano coinvolti processi con archi esclusivamente entranti. Ogni processo appartenente a questa categoria non è in attesa di risorse, e può dunque procedere con i suoi calcoli; quando avrà terminato rilascerà le risorse precedentemente allocategli, eventualmente sbloccando uno dei processi coinvolti nel ciclo.&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;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
proc[x]: x='a',...,'z'&lt;br /&gt;
 while True:&lt;br /&gt;
  //c sarà il carattere stampato dal processo precedente&lt;br /&gt;
  (c, string) = arecv(*)&lt;br /&gt;
  if(string == wait){&lt;br /&gt;
    //mi metto in attesa di ricevere l'ACK da proc[x]&lt;br /&gt;
    m=arecv(x);&lt;br /&gt;
  }&lt;br /&gt;
  if (c == NONE){&lt;br /&gt;
    //significa che sei il primo a ricevere quella stringa&lt;br /&gt;
    print(x);&lt;br /&gt;
    if (len(string) &amp;gt; 1){&lt;br /&gt;
      //mando la wait a tutti, il primo che riceve qualcosa da stampare manda una wait a tutti&lt;br /&gt;
      asend(wait,*);&lt;br /&gt;
      int l = len(string);&lt;br /&gt;
      int i = 1;&lt;br /&gt;
      while(l != 0){&lt;br /&gt;
        asend(proc[string[i]], (x, string[i...]));&lt;br /&gt;
        //si mette in attesa di ricevere l'ACK dal processo dell'ultima lettera della parola&lt;br /&gt;
        m=areceive(proc[string[i]]);&lt;br /&gt;
        //rimando la wait al processo per ribloccarlo&lt;br /&gt;
        asend(wait, proc[string[i]])&lt;br /&gt;
        l--;&lt;br /&gt;
        i++;&lt;br /&gt;
      }&lt;br /&gt;
      //dopo aver finito la stampa della stringa sblocco tutti i processi&lt;br /&gt;
      asend(ACK, *);&lt;br /&gt;
    }&lt;br /&gt;
  }else{&lt;br /&gt;
    print(x);&lt;br /&gt;
    asend(ACK, x);&lt;br /&gt;
    //ricomincia il ciclo while, si rimette in attesa e il 'gestore gli rimanda la wait'&lt;br /&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;
&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;
&lt;br /&gt;
monitor bridge:&lt;br /&gt;
&lt;br /&gt;
    int ncar&lt;br /&gt;
    bool boat_on_0&lt;br /&gt;
    bool boat_on_1       // per semplicità, quando nel codice si trova boat_on_(direction) oppure isBoat(direction)(),&lt;br /&gt;
                         // si valuta il valore booleano di direction e lo si applica sotto forma di stringa al simbolo&lt;br /&gt;
                         // ad esso adiacente&lt;br /&gt;
    bool is_raised&lt;br /&gt;
    queue waiting_mean   // i valori possibili sono: boat0, boat1 oppure car&lt;br /&gt;
    condition ok2go&lt;br /&gt;
  &lt;br /&gt;
    entry car_enter(direction): &lt;br /&gt;
        if is_raised || ncar == MAXCAR:&lt;br /&gt;
            waiting_mean.enqueue(car)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        is_raised = false&lt;br /&gt;
        ++ncar&lt;br /&gt;
  &lt;br /&gt;
    entry car_exit(direction):&lt;br /&gt;
        --ncar&lt;br /&gt;
        if (waiting_mean.top().isBoat() &amp;amp;&amp;amp; ncar == 0) || waiting_mean.top().isCar():    // isBoat ritorna true se l'oggetto su cui&lt;br /&gt;
            waiting_mean.dequeue()                                                      // è invocata è boat0 oppure boat1&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
  &lt;br /&gt;
    entry boat_enter(direction):&lt;br /&gt;
        if !is_raised || boat_on_(direction):&lt;br /&gt;
            waiting_mean.enqueue(boat)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        if waiting_mean.top().isBoat(!direction)():&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
        is_raised = true&lt;br /&gt;
        boat_on_(direction) = true&lt;br /&gt;
  &lt;br /&gt;
    entry boat_exit(direction):&lt;br /&gt;
        boat_on_(direction) = false&lt;br /&gt;
        if !boat_on_(!direction):&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
&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;
=== 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;
entry 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;
entry 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;
entry 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;
entry 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 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge {&lt;br /&gt;
&lt;br /&gt;
  UP=0;&lt;br /&gt;
  DOWN=1;&lt;br /&gt;
  bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
  bool carAreExiting = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2drive;&lt;br /&gt;
  condition ok2barca[2];&lt;br /&gt;
&lt;br /&gt;
  waitingCar = 0;&lt;br /&gt;
  carOnBridge = 0;&lt;br /&gt;
&lt;br /&gt;
  boatWaiting[2] = {0,0};&lt;br /&gt;
  boatIsPassing[2] = {false,false}&lt;br /&gt;
&lt;br /&gt;
  entry car_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == DOWN)&lt;br /&gt;
      if(carOnBridge == MAXCAR)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
      else if (carAreExiting)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
    else &lt;br /&gt;
      if (boatIsPassing[0] || boatIsPassing[1])&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
    carOnBridge++;&lt;br /&gt;
    carAreExiting = false;&lt;br /&gt;
    if(carOnBridge &amp;lt; MAXCAR &amp;amp;&amp;amp; !carAreExiting) &lt;br /&gt;
      ok2drive.signal();&lt;br /&gt;
      &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry car_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    carOnBridge--;&lt;br /&gt;
    carAreExiting = true;&lt;br /&gt;
&lt;br /&gt;
    if(carOnBridge == 0)&lt;br /&gt;
      carAreExiting = false;&lt;br /&gt;
      if(boatWaiting[0] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[0].signal();&lt;br /&gt;
      else if (boatWaiting[1] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[1].signal();&lt;br /&gt;
      else &lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == UP)&lt;br /&gt;
    | if (boatIsPassing[direction] == true)&lt;br /&gt;
    | |  boatWaiting[direction]++;&lt;br /&gt;
    | |  ok2barca.wait();&lt;br /&gt;
    | |  boatWaiting[direction]--;&lt;br /&gt;
    else &lt;br /&gt;
    | if (carOnBridge &amp;gt; 0)&lt;br /&gt;
    | | boatWaiting[direction]++;&lt;br /&gt;
    | | ok2barca.wait();&lt;br /&gt;
    | | boatWaiting[direction]--;&lt;br /&gt;
    | | bridgeis = UP;&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = true;&lt;br /&gt;
&lt;br /&gt;
    if(boatIsPassing[1-direction] == false &amp;amp;&amp;amp; boatWaiting[1-direction] &amp;gt; 0)&lt;br /&gt;
      ok2barca[1-direction].signal();&lt;br /&gt;
    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = false;&lt;br /&gt;
&lt;br /&gt;
    if (boatIsPassing[1-direction] == false)&lt;br /&gt;
      if (waitingCar &amp;gt; 0)&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
    else&lt;br /&gt;
        if (waitingCar == 0)&lt;br /&gt;
          ok2barca[direction].signal();&lt;br /&gt;
          &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&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;
entry 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;
entry 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;
entry 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;
entry 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;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
# (Ri)Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 26/08/2020&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
list printed_msg;  # questa è una variabile condivisa che ai fini dell'esercizio non si può utilizzare (message passing)&lt;br /&gt;
&lt;br /&gt;
process server[i]:&lt;br /&gt;
  while true:&lt;br /&gt;
    &amp;lt;msg, pid&amp;gt; = arecv(*)&lt;br /&gt;
&lt;br /&gt;
    if printed_msg.length == 0 or &amp;lt;msg, pid&amp;gt; is not in printed_msg:&lt;br /&gt;
      printed_msg.append(&amp;lt;msg,id&amp;gt;)&lt;br /&gt;
      print(msg)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
Nello svolgimento seguente, receiver incapsula l'ambiente privato del processo; _peers rappresenta il vettore di processi &amp;quot;fratelli&amp;quot; ai quali può essere chiesto di stampare un messaggio, mentre _printed contiene l'hash di tutti i messaggi stampati dal processo locale. Si suppone che istanze della classe receiver possano essere passate come parametro ad areceive() ed asend() (non implementate).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class receiver:&lt;br /&gt;
    def __init__(self, peers):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param peers: list of processes this process communicates with.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self._peers = tuple(peers)&lt;br /&gt;
        self._printed = list()&lt;br /&gt;
    &lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            process, message = areceive(ANY)&lt;br /&gt;
&lt;br /&gt;
            if process in self._peers:&lt;br /&gt;
                self._reply_query(process, message)&lt;br /&gt;
            else:&lt;br /&gt;
                self._print(process, message)&lt;br /&gt;
&lt;br /&gt;
    def _print(self, sender, message):&lt;br /&gt;
        h = hash(message.text)&lt;br /&gt;
&lt;br /&gt;
        if h not in self._printed and not self._printed_from_peers(message):&lt;br /&gt;
            self._printed.append(h)&lt;br /&gt;
            print(message.text)&lt;br /&gt;
&lt;br /&gt;
    def _reply_query(self, sender, h):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Invoked when the current process receive a &amp;quot;query&amp;quot; from a peer process.&lt;br /&gt;
        `h` contains the hash of a message which may or may have not been&lt;br /&gt;
        sent from this process; if it was sent, the reply is `Yes`, otherwise `No`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        reply = &amp;quot;Yes&amp;quot; if int(h) in self._printed else &amp;quot;No&amp;quot;&lt;br /&gt;
        asend(sender, reply)&lt;br /&gt;
&lt;br /&gt;
    def _printed_from_peers(self, message):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `True` if this message has already been printed from any of the&lt;br /&gt;
        peer processes, `False` otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        h = hash(message)&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            asend(p, str(h))&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            _, reply = areceive(p)&lt;br /&gt;
&lt;br /&gt;
            if reply.text == &amp;quot;Yes&amp;quot;:&lt;br /&gt;
                return True&lt;br /&gt;
            else if reply.text != &amp;quot;No&amp;quot;:&lt;br /&gt;
                # If the response is neither &amp;quot;Yes&amp;quot; nor &amp;quot;No&amp;quot;, then we have got a query&lt;br /&gt;
                self._reply_query(p, reply)&lt;br /&gt;
&lt;br /&gt;
        return False&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Sulla base dei valori in entrata, è possibile costruire le matrici Allocation (q.tà di risorse allocate per processo e per tipo), Need (q.tà di risorse che ogni processo potrebbe ancora chiedere) e il vettore Available (num. di risorse correntemente disponibili).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left&amp;quot;&lt;br /&gt;
! colspan=3 | Allocation&lt;br /&gt;
|-&lt;br /&gt;
   !   !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 4 || 5&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 3 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 2 || 4&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=3 | Need&lt;br /&gt;
|-&lt;br /&gt;
   !    !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 6 || 8&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 6 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 6 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=2 | Available&lt;br /&gt;
|-&lt;br /&gt;
   ! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | x || y&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nel caso delle risorse di tipo A, deve aversi x &amp;gt;= 6 in quanto un processo dovrà essere selezionato come primo nella permutazione dell'algoritmo del banchiere multivaluta, e tutti quelli correnti hanno lo stesso valore Need(i)(1); per ciò che riguarda le risorse di tipo B, possiamo ragionare per esaustione&lt;br /&gt;
&lt;br /&gt;
* Se il primo processo della permutazione è p1, allora y &amp;gt;= 8 (con questo valore posso soddisfare la richiesta di p1 e in seguito tutte le altre)&lt;br /&gt;
* Se il primo processo della permutazione è p2, allora y &amp;gt;= 5: con questo valore è possibile soddisfare la richiesta di p2; una volta che esso avrà finito, restituirà 3 unità della risorsa B, che permetteranno di soddisfare sia le richieste di A sia quelle di C&lt;br /&gt;
* Se il primo processo della permutazione è p3, allora y &amp;gt;= 8 (ragionamento analogo come per p1)&lt;br /&gt;
&lt;br /&gt;
Volendo scegliere il minimo, y &amp;gt;= 5, ed in conclusione (x, y) &amp;gt;= (6, 5).&lt;br /&gt;
&lt;br /&gt;
''Svolgimento basato in parte sull'approccio di Operating System Concepts di Silberschatz. et al, 9th edition, cap. 7.''&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# Può accadere che il sistema torni in uno stato di safety o che invece porti a deadlock. Diversamente uno stato di safety non può portare direttamente ad uno stato di deadlock, ma solo ad uno di non-safety.&lt;br /&gt;
# Selezionare uno o più tra i processi attivi e sospenderli, salvando il loro stato su memoria secondaria operando delle operazioni di swap-out, finché l'insieme dei frame nella memoria centrale non è in grado di soddisfare tutti i processi rimasti attivi.&lt;br /&gt;
# La scelta è determinata perlopiù dal fattore costo. Con un sistema RAID 1 è possibile ripristinare un disco guasto molto brevemente, in quanto le operazioni coinvolte prevedono una semplice ricopiatura dal disco di backup; con un sistema RAID 5 il ripristino del disco guasto deve coinvolgere tutti i dischi dell'intero array, e ciò può richiedere anche ore per dischi di grandi dimensioni. D'altra parte RAID 1 è più costoso (con n dischi, posso memorizzare tanta informazione quanto potrei con n / 2 dischi) rispetto a RAID 5 dove, tra gli n dischi, complessivamente soltanto uno è destinato alle informazioni di ridondanza.&lt;br /&gt;
# ''Completare.''&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;
        entry 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;
        entry 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;
        entry 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;
&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;
si, è possibile: &lt;br /&gt;
&lt;br /&gt;
Implementare asend e arecv date bsend e brecv&lt;br /&gt;
&lt;br /&gt;
asend(pid_t, msg_type msg){&lt;br /&gt;
    bsend (&amp;lt;pid_t dst, msg&amp;gt;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
arecv(*){&lt;br /&gt;
  pid_t act = getpid(); \\ act = proprio pid &lt;br /&gt;
  do{&lt;br /&gt;
    &amp;lt;dst, msg&amp;gt; = brecv(*);&lt;br /&gt;
  }while (dst =! act)&lt;br /&gt;
  return msg;&lt;br /&gt;
}&lt;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;
entry 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;
entry 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;
entry 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;
monitor altcolbb {&lt;br /&gt;
&lt;br /&gt;
  generic_type valueBuf[MAX];&lt;br /&gt;
  int front = rear = 0;&lt;br /&gt;
&lt;br /&gt;
  bool isFull = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write[2]; //gli indici sono i colori (red=0, blue=1)&lt;br /&gt;
&lt;br /&gt;
  lastColor = None;&lt;br /&gt;
&lt;br /&gt;
  entry void write(color_t color, generic_type val) {&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
        if(isFull)&lt;br /&gt;
          ok2write[color].wait();&lt;br /&gt;
    else&lt;br /&gt;
      if (lastColor == color)&lt;br /&gt;
        ok2write[color].wait();&lt;br /&gt;
              &lt;br /&gt;
    valueBuf[front] = val;&lt;br /&gt;
    front = (front+1) % MAX;&lt;br /&gt;
    lastColor = color;&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
      isFull = true;&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-color].signal();&lt;br /&gt;
&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
        &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry generic_type read(void) {&lt;br /&gt;
&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      if (!isFull)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
&lt;br /&gt;
    generic_type tmpValue = valueBuf[rear];&lt;br /&gt;
    &lt;br /&gt;
    rear = (rear + 1) % MAX;&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      isFull = false;&lt;br /&gt;
      color_t tmpColor = lastColor;&lt;br /&gt;
      lastColor = None;&lt;br /&gt;
      ok2write[tmpColor].signal();  //quando un lettore legge l'ultimo elemento&lt;br /&gt;
                                    //dal buffer, ci possono solo essere scrittori&lt;br /&gt;
                                    //in attesa che abbiano lo stesso colore&lt;br /&gt;
                                    //dell'ultimo elemento.&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-lastColor].signal();&lt;br /&gt;
      &lt;br /&gt;
    return tmpValue;&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;
&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 c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
Il programma dispone di una mutex per l'accesso protetto alla variabile n, e dei due semafori s1 ed s2 per regolare l'alternanza tra i thread A e AB. Sulla base di essi, e del fatto che entrambi i thread eseguono 2 cicli, è possibile affermare (verificare) che&lt;br /&gt;
&lt;br /&gt;
* L'alternanza dei due thread è A-AB-A-AB o&lt;br /&gt;
* L'alternanza dei due thread è AB-A-AB-A&lt;br /&gt;
&lt;br /&gt;
Infatti se il thread A svolgesse due cicli consecutivamente, invocherebbe s1.P() due volte senza fare mai ricorso a s1.V() (ragionamento analogo per AB); pertanto è necessario attendere l'intervento dell'altro thread in attesa di una chiamata su s1.V().&lt;br /&gt;
&lt;br /&gt;
Per concludere, i possibili valori di n al termine del programma saranno, in corrispondenza delle due diramazioni elencate sopra&lt;br /&gt;
&lt;br /&gt;
* n = 12&lt;br /&gt;
* n = 5&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente [[User:Acsor|Acsor]] in data 23/08/2020. Ritengo sia: corretto&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&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;
==== Punto b) ====&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;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
# Frammentazione interna: allocazioni di pagine la cui dimensione è strettamente maggiore di quella effettivamente richiesta.  Frammentazione esterna: nessuno. Infatti ogni spazio (pagina) allocato e liberato è prima o poi riallocato.&lt;br /&gt;
# Se non viene utilizzato un sistema di caching, una lettura diretta a più blocchi di un file di grandi dimensioni richiede: la lettura della FAT, solitamente posta all'inizio di un [[Glossario#Volume|volume]] (e dunque, su dischi rotazionali, in una traccia differente da quella attuale o da quella del blocco da leggere); la lettura del blocco stesso, e dunque lo spostamento della testina nella traccia e nel settore di interesse&lt;br /&gt;
# Uno scheduling a priorità statica può essere utile ad un processo interattivo, dove è necessario mantenersi all'interno di date soglie temporali o semplicemente svolgere un dato compito con meno ritardo possibile; esempi concreti: un processo che faccia streaming video; un processo appartenente ad un server il cui obiettivo primario è soddisfare le richieste dei propri client il prima possibile, ma dove può anche essere svolta qualche attività dai processi locali (es. programmi applicativi). In uno scheduling a priorità statica, se la presenza di processi ad alte priorità è costante, possono verificarsi indesiderati fenomeni di ''starvation'' nei confronti di processi meno prioritari.&lt;br /&gt;
# ''Domanda puramente nozionistica, la cui risposta può essere ricavata consultando note, lucidi o libri di testo.''&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&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;
    if (buffer.lenght() &amp;gt;= MAX) {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX) {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&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;
    generic_type val;&lt;br /&gt;
&lt;br /&gt;
    if (buffer.lenght() == 0) {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&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;
&lt;br /&gt;
    val = buffer.length() == 0 ? NULL: buffer.dequeue();&lt;br /&gt;
    ok2write.signal();&lt;br /&gt;
&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 ===&lt;br /&gt;
&lt;br /&gt;
* Controllato e corretto dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&lt;br /&gt;
===== Algoritmo MIN =====&lt;br /&gt;
&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;
===== Algoritmo 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;
==== Punto b) ====&lt;br /&gt;
&lt;br /&gt;
Poiché non è specificato quale dei due algoritmi precedenti applicare, sono state considerate soluzioni per ognuno di essi&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo MIN (da controllare) =====&lt;br /&gt;
(È possibile ottenere una stringa più breve?)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
4 3 2 1 5 3 2 1 4 5 3 2 1 3 2 4 5 1 2 4 3 1 5 4 2 1 3 4   &lt;br /&gt;
-------------------------------------------------------&lt;br /&gt;
4|4|4|4|5|  5  |5|  5  |1|  1  |1|  1  |1|  1  |   1   &lt;br /&gt;
 |3|3|3|3|  3  |3|  3  |3|  3  |5|  5  |5|  5  |   2   &lt;br /&gt;
 | |2|2|2|  2  |2|  2  |2|  2  |2|  2  |3|  3  |   3   &lt;br /&gt;
 | | |1|1|  1  |4|  4  |4|  4  |4|  4  |4|  4  |   4   &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo LRU =====&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 1 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 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 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;br /&gt;
&lt;br /&gt;
== Esame Pratico 22/01/2016 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2016.01.22.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dirent.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef struct nameNumber {&lt;br /&gt;
        char *name;&lt;br /&gt;
        int value;&lt;br /&gt;
    } nameNumber;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int prefixToInt (char *string) {&lt;br /&gt;
&lt;br /&gt;
    int i = 0;&lt;br /&gt;
    int num = 0;&lt;br /&gt;
    while (string[i] &amp;gt;= '0' &amp;amp;&amp;amp; string[i] &amp;lt; '9' &amp;amp;&amp;amp; i &amp;lt; strlen(string)) {&lt;br /&gt;
        num = (num*10) + (string[i]-'0');&lt;br /&gt;
        i++;&lt;br /&gt;
    }&lt;br /&gt;
    return num;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void fileSort(struct nameNumber **files) {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int comp (const void * el1, const void * el2) {&lt;br /&gt;
    struct nameNumber *f = *((nameNumber**)el1);&lt;br /&gt;
    struct nameNumber *s = *((nameNumber**)el2);&lt;br /&gt;
    if (f-&amp;gt;value &amp;gt; s-&amp;gt;value) return 1;&lt;br /&gt;
    if (f-&amp;gt;value &amp;lt; s-&amp;gt;value) return -1;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int arg, char* argv[]) {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    struct nameNumber **files;&lt;br /&gt;
&lt;br /&gt;
    DIR *dir;&lt;br /&gt;
    struct dirent *ent;&lt;br /&gt;
&lt;br /&gt;
    int count = 0;&lt;br /&gt;
&lt;br /&gt;
    if((dir = opendir(argv[1])) != NULL) &lt;br /&gt;
    {&lt;br /&gt;
        while( (ent = readdir(dir)) != NULL ) &lt;br /&gt;
        {   &lt;br /&gt;
            if (ent-&amp;gt;d_name[0] &amp;lt; '9' &amp;amp;&amp;amp; ent-&amp;gt;d_name[0] &amp;gt;= '0') &lt;br /&gt;
            {&lt;br /&gt;
                files = (struct nameNumber**)realloc(files , (count+1) * sizeof(struct nameNumber*));&lt;br /&gt;
                files[count] = (struct nameNumber*)malloc(sizeof(struct nameNumber));&lt;br /&gt;
                files[count]-&amp;gt;name = (char*)malloc(sizeof(char)*strlen(ent-&amp;gt;d_name) + 1);&lt;br /&gt;
                strcpy(files[count]-&amp;gt;name, ent-&amp;gt;d_name);&lt;br /&gt;
                files[count]-&amp;gt;value = prefixToInt(files[count]-&amp;gt;name);&lt;br /&gt;
                printf(&amp;quot;name : %s  ,  value : %d\n&amp;quot;, files[count]-&amp;gt;name , files[count]-&amp;gt;value);&lt;br /&gt;
                count++;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    qsort(files, count, sizeof(nameNumber*), comp);&lt;br /&gt;
&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i=0; i &amp;lt; count; i++) {&lt;br /&gt;
        printf(&amp;quot;%s\n&amp;quot;,files[i]-&amp;gt;name);&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;
&lt;br /&gt;
== Esame di Concorrenza del 13/01/2005 ==&lt;br /&gt;
Il testo degli esercizi è disponibile alla pagina http://www.cs.unibo.it/~renzo/so/compiti/2005-01-13.con.pdf.&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
Il codice di questo esercizio può essere eseguito scaricando il sorgente Python e l'archivio relativo agli [[Tool_per_semafori_e_monitor|strumenti di concorrenza per il linguaggio Python]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
import threading&lt;br /&gt;
import random&lt;br /&gt;
import time&lt;br /&gt;
from pysm.semaphore import semaphore&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class mod_counter:&lt;br /&gt;
    def __init__(self, mod, start=0):&lt;br /&gt;
        self._mod = mod&lt;br /&gt;
        self._val = start&lt;br /&gt;
&lt;br /&gt;
    def inc(self):&lt;br /&gt;
        self._val = (self._val + 1) % self._mod&lt;br /&gt;
&lt;br /&gt;
    def get(self):&lt;br /&gt;
        return self._val&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class process(threading.Thread):&lt;br /&gt;
    def __init__(self, to_print, c: mod_counter, a, t, r):&lt;br /&gt;
        threading.Thread.__init__(self, name=&amp;quot;proc&amp;quot; + to_print)&lt;br /&gt;
&lt;br /&gt;
        if to_print not in &amp;quot;tar&amp;quot;:&lt;br /&gt;
            raise ValueError(&amp;quot;Unexpected printable character:&amp;quot;, to_print)&lt;br /&gt;
&lt;br /&gt;
        self._counter = c&lt;br /&gt;
        self._x = to_print&lt;br /&gt;
        self._semaphores = {'t': t, 'a': a, 'r': r}&lt;br /&gt;
        self._enter = True&lt;br /&gt;
&lt;br /&gt;
        if self._x == 't':&lt;br /&gt;
            self._semaphores[self._x].V()&lt;br /&gt;
&lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            self.sync()&lt;br /&gt;
            print(&amp;quot;[%s] %c&amp;quot; % (self.name, self._x))&lt;br /&gt;
&lt;br /&gt;
            # Print a trailing newline&lt;br /&gt;
            if (self._counter.get() == 7):&lt;br /&gt;
                print()&lt;br /&gt;
&lt;br /&gt;
            time.sleep(random.random() * 0.5)&lt;br /&gt;
&lt;br /&gt;
    def sync(self):&lt;br /&gt;
        if (self._enter):&lt;br /&gt;
            self._semaphores[self._x].P()&lt;br /&gt;
            self._enter = False&lt;br /&gt;
        else:&lt;br /&gt;
            self._counter.inc()&lt;br /&gt;
            curr = &amp;quot;taratata&amp;quot;[self._counter.get()]&lt;br /&gt;
&lt;br /&gt;
            self._semaphores[curr].V()&lt;br /&gt;
&lt;br /&gt;
            self._enter = True&lt;br /&gt;
            self.sync()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    counter = mod_counter(8)&lt;br /&gt;
    semaphores = (semaphore(0), semaphore(0), semaphore(0))&lt;br /&gt;
    procs = [process(c, counter, *semaphores) for c in &amp;quot;tar&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.daemon = True&lt;br /&gt;
        p.start()&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Tool_per_semafori_e_monitor&amp;diff=2572</id>
		<title>Tool per semafori e monitor</title>
		<link rel="alternate" type="text/html" href="https://so.v2.cs.unibo.it/wiki/index.php?title=Tool_per_semafori_e_monitor&amp;diff=2572"/>
		<updated>2020-08-28T13:21:32Z</updated>

		<summary type="html">&lt;p&gt;Acsor: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I seguenti archivi forniscono strumenti di programmazione concorrente per i linguaggi C e Python&lt;br /&gt;
&lt;br /&gt;
* [http://www.cs.unibo.it/~renzo/so/tools/sm.tgz tool per provare i semafori in C]&lt;br /&gt;
* [http://www.cs.unibo.it/~renzo/so/tools/pysm.tgz tool per provare i semafori in Python]&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2571</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=2571"/>
		<updated>2020-08-27T19:31:04Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.2 (sbagliato) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina raccoglie prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review. Chiunque prenda visione di un esercizio è pregato (per il bene collettivo) a lasciare una [https://www.mediawiki.org/wiki/Help:Signatures propria firma] con nome utente e data di visualizzazione indicando se lo svolgimento è ritenuto corretto; in caso di svolgimento scorretto è invece invitato ad apportare una correzione, lasciando come nel caso precedente il proprio nome utente e data di correzione.&lt;br /&gt;
&lt;br /&gt;
Al fine di verificare la correttezza degli esercizi di concorrenza, segnaliamo la presenza di [[Tool_per_semafori_e_monitor|strumenti di programmazione concorrente]] per i linguaggi C e Python.&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&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 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente Lusvelt in data 26/08/2020 (sbagliato, dal testo si evince che se manca anche solo un componente bisogna mettersi in attesa finchè non arrivi, per poi prendere anche gli altri).&lt;br /&gt;
:: E non è quel che già accade nel ramo else di get()? C'è una wait() ed essa è invocata proprio quando components[i] &amp;gt; self._v[i]. (La chat in Wiki è scomoda, sentiamoci su Telegram.) -- [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:32, 26 August 2020 (CEST)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
    altri operai in attesa.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (possibile soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&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 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Nello pseudocodice seguente, il termine this fa riferimento al processo corrente, mentre ANY ad uno qualunque.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack&amp;lt;message&amp;gt; messages;&lt;br /&gt;
&lt;br /&gt;
void lifo_send(string m, process dest) {&lt;br /&gt;
	do {&lt;br /&gt;
		asend(m, dest);&lt;br /&gt;
	} while (areceive(dest).text != &amp;quot;ACK&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
message lifo_receive(process source) {&lt;br /&gt;
	if (source != ANY) {&lt;br /&gt;
		message m = areceive(source);&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;ACK&amp;quot;, source);&lt;br /&gt;
&lt;br /&gt;
		return m;&lt;br /&gt;
	} else {&lt;br /&gt;
		message m;&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;END&amp;quot;, this);&lt;br /&gt;
		m = areceive(ANY);&lt;br /&gt;
&lt;br /&gt;
		while (m.text != &amp;quot;END&amp;quot; || m.sender != this) {&lt;br /&gt;
			messages.push(m);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                /* Bisogna tenere conto dei casi in cui lifo_receive() viene invocata quando nessun&lt;br /&gt;
                 * messaggio è stato ancora spedito da altri processi. In tal caso si attende il&lt;br /&gt;
                 * il primo e lo si restituisce.&lt;br /&gt;
                 */&lt;br /&gt;
		if (messages.empty()) {&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			return m;&lt;br /&gt;
		} else {&lt;br /&gt;
			return messages.pop();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&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;
* Visto e corretto dall'utente [[User:Acsor|Acsor]] in data 23/08/2020&lt;br /&gt;
* Visto e corretto dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
class LIFOBuffer {&lt;br /&gt;
	stack&amp;lt;T&amp;gt; s;&lt;br /&gt;
	semaphore mutex(1); // mutua esclusione&lt;br /&gt;
	semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
	void push (T value) {&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		s.push(value);&lt;br /&gt;
                // (1)&lt;br /&gt;
		mutex.V()&lt;br /&gt;
&lt;br /&gt;
		ok2consume.V()  // Curiosità: che succede se spostiamo quest'istruzione in (1)?&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	T pop () {&lt;br /&gt;
		T value;&lt;br /&gt;
&lt;br /&gt;
		ok2consume.P();&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		value = s.pop();&lt;br /&gt;
		mutex.V();&lt;br /&gt;
&lt;br /&gt;
		return value;&lt;br /&gt;
	}&lt;br /&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;
# In sistemi dove dispositivi di archiviazione o supporti hardware per la memoria virtuale (e dunque per la paginazione, spesso utilizzata per realizzare il supporto di memoria virtuale) non sono presenti (es. sistemi embedded). ''(In sistemi real-time la memoria virtuale è praticabile? Annotare.)''&lt;br /&gt;
# 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.&lt;br /&gt;
# Per fornire parallelismo e ridondanza. Non è necessario fare backup dei dati sul disco, nel senso di mantenere una copia identica di dati già memorizzati altrove, in quanto diversi sistemi di codici permettono il rilevamento e/o la correzione di errori.&lt;br /&gt;
# Se in un grafo di Holt multirisorsa esiste un ciclo tra più processi e risorse, ciò non significa che allo stesso tempo non siano coinvolti processi con archi esclusivamente entranti. Ogni processo appartenente a questa categoria non è in attesa di risorse, e può dunque procedere con i suoi calcoli; quando avrà terminato rilascerà le risorse precedentemente allocategli, eventualmente sbloccando uno dei processi coinvolti nel ciclo.&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;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
proc[x]: x='a',...,'z'&lt;br /&gt;
 while True:&lt;br /&gt;
  //c sarà il carattere stampato dal processo precedente&lt;br /&gt;
  (c, string) = arecv(*)&lt;br /&gt;
  if(string == wait){&lt;br /&gt;
    //mi metto in attesa di ricevere l'ACK da proc[x]&lt;br /&gt;
    m=arecv(x);&lt;br /&gt;
  }&lt;br /&gt;
  if (c == NONE){&lt;br /&gt;
    //significa che sei il primo a ricevere quella stringa&lt;br /&gt;
    print(x);&lt;br /&gt;
    if (len(string) &amp;gt; 1){&lt;br /&gt;
      //mando la wait a tutti, il primo che riceve qualcosa da stampare manda una wait a tutti&lt;br /&gt;
      asend(wait,*);&lt;br /&gt;
      int l = len(string);&lt;br /&gt;
      int i = 1;&lt;br /&gt;
      while(l != 0){&lt;br /&gt;
        asend(proc[string[i]], (x, string[i...]));&lt;br /&gt;
        //si mette in attesa di ricevere l'ACK dal processo dell'ultima lettera della parola&lt;br /&gt;
        m=areceive(proc[string[i]]);&lt;br /&gt;
        //rimando la wait al processo per ribloccarlo&lt;br /&gt;
        asend(wait, proc[string[i]])&lt;br /&gt;
        l--;&lt;br /&gt;
        i++;&lt;br /&gt;
      }&lt;br /&gt;
      //dopo aver finito la stampa della stringa sblocco tutti i processi&lt;br /&gt;
      asend(ACK, *);&lt;br /&gt;
    }&lt;br /&gt;
  }else{&lt;br /&gt;
    print(x);&lt;br /&gt;
    asend(ACK, x);&lt;br /&gt;
    //ricomincia il ciclo while, si rimette in attesa e il 'gestore gli rimanda la wait'&lt;br /&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;
&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;
&lt;br /&gt;
monitor bridge:&lt;br /&gt;
&lt;br /&gt;
    int ncar&lt;br /&gt;
    bool boat_on_0&lt;br /&gt;
    bool boat_on_1       // per semplicità, quando nel codice si trova boat_on_(direction) oppure isBoat(direction)(),&lt;br /&gt;
                         // si valuta il valore booleano di direction e lo si applica sotto forma di stringa al simbolo&lt;br /&gt;
                         // ad esso adiacente&lt;br /&gt;
    bool is_raised&lt;br /&gt;
    queue waiting_mean   // i valori possibili sono: boat0, boat1 oppure car&lt;br /&gt;
    condition ok2go&lt;br /&gt;
  &lt;br /&gt;
    entry car_enter(direction): &lt;br /&gt;
        if is_raised || ncar == MAXCAR:&lt;br /&gt;
            waiting_mean.enqueue(car)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        is_raised = false&lt;br /&gt;
        ++ncar&lt;br /&gt;
  &lt;br /&gt;
    entry car_exit(direction):&lt;br /&gt;
        --ncar&lt;br /&gt;
        if (waiting_mean.top().isBoat() &amp;amp;&amp;amp; ncar == 0) || waiting_mean.top().isCar():    // isBoat ritorna true se l'oggetto su cui&lt;br /&gt;
            waiting_mean.dequeue()                                                      // è invocata è boat0 oppure boat1&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
  &lt;br /&gt;
    entry boat_enter(direction):&lt;br /&gt;
        if !is_raised || boat_on_(direction):&lt;br /&gt;
            waiting_mean.enqueue(boat)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        if waiting_mean.top().isBoat(!direction)():&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
        is_raised = true&lt;br /&gt;
        boat_on_(direction) = true&lt;br /&gt;
  &lt;br /&gt;
    entry boat_exit(direction):&lt;br /&gt;
        boat_on_(direction) = false&lt;br /&gt;
        if !boat_on_(!direction):&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
&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;
=== 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;
entry 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;
entry 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;
entry 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;
entry 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 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge {&lt;br /&gt;
&lt;br /&gt;
  UP=0;&lt;br /&gt;
  DOWN=1;&lt;br /&gt;
  bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
  bool carAreExiting = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2drive;&lt;br /&gt;
  condition ok2barca[2];&lt;br /&gt;
&lt;br /&gt;
  waitingCar = 0;&lt;br /&gt;
  carOnBridge = 0;&lt;br /&gt;
&lt;br /&gt;
  boatWaiting[2] = {0,0};&lt;br /&gt;
  boatIsPassing[2] = {false,false}&lt;br /&gt;
&lt;br /&gt;
  entry car_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == DOWN)&lt;br /&gt;
      if(carOnBridge == MAXCAR)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
      else if (carAreExiting)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
    else &lt;br /&gt;
      if (boatIsPassing[0] || boatIsPassing[1])&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
    carOnBridge++;&lt;br /&gt;
    carAreExiting = false;&lt;br /&gt;
    if(carOnBridge &amp;lt; MAXCAR &amp;amp;&amp;amp; !carAreExiting) &lt;br /&gt;
      ok2drive.signal();&lt;br /&gt;
      &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry car_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    carOnBridge--;&lt;br /&gt;
    carAreExiting = true;&lt;br /&gt;
&lt;br /&gt;
    if(carOnBridge == 0)&lt;br /&gt;
      carAreExiting = false;&lt;br /&gt;
      if(boatWaiting[0] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[0].signal();&lt;br /&gt;
      else if (boatWaiting[1] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[1].signal();&lt;br /&gt;
      else &lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == UP)&lt;br /&gt;
    | if (boatIsPassing[direction] == true)&lt;br /&gt;
    | |  boatWaiting[direction]++;&lt;br /&gt;
    | |  ok2barca.wait();&lt;br /&gt;
    | |  boatWaiting[direction]--;&lt;br /&gt;
    else &lt;br /&gt;
    | if (carOnBridge &amp;gt; 0)&lt;br /&gt;
    | | boatWaiting[direction]++;&lt;br /&gt;
    | | ok2barca.wait();&lt;br /&gt;
    | | boatWaiting[direction]--;&lt;br /&gt;
    | | bridgeis = UP;&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = true;&lt;br /&gt;
&lt;br /&gt;
    if(boatIsPassing[1-direction] == false &amp;amp;&amp;amp; boatWaiting[1-direction] &amp;gt; 0)&lt;br /&gt;
      ok2barca[1-direction].signal();&lt;br /&gt;
    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = false;&lt;br /&gt;
&lt;br /&gt;
    if (boatIsPassing[1-direction] == false)&lt;br /&gt;
      if (waitingCar &amp;gt; 0)&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
    else&lt;br /&gt;
        if (waitingCar == 0)&lt;br /&gt;
          ok2barca[direction].signal();&lt;br /&gt;
          &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&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;
entry 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;
entry 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;
entry 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;
entry 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;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&lt;br /&gt;
# (Ri)Controllato dall'utente [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) in data 26/08/2020&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
list printed_msg;  # questa è una variabile condivisa che ai fini dell'esercizio non si può utilizzare (message passing)&lt;br /&gt;
&lt;br /&gt;
process server[i]:&lt;br /&gt;
  while true:&lt;br /&gt;
    &amp;lt;msg, pid&amp;gt; = arecv(*)&lt;br /&gt;
&lt;br /&gt;
    if printed_msg.length == 0 or &amp;lt;msg, pid&amp;gt; is not in printed_msg:&lt;br /&gt;
      printed_msg.append(&amp;lt;msg,id&amp;gt;)&lt;br /&gt;
      print(msg)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
Nello svolgimento seguente, receiver incapsula l'ambiente privato del processo; _peers rappresenta il vettore di processi &amp;quot;fratelli&amp;quot; ai quali può essere chiesto di stampare un messaggio, mentre _printed contiene l'hash di tutti i messaggi stampati dal processo locale. Si suppone che istanze della classe receiver possano essere passate come parametro ad areceive() ed asend() (non implementate).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class receiver:&lt;br /&gt;
    def __init__(self, peers):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param peers: list of processes this process communicates with.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self._peers = tuple(peers)&lt;br /&gt;
        self._printed = list()&lt;br /&gt;
    &lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            process, message = areceive(ANY)&lt;br /&gt;
&lt;br /&gt;
            if process in self._peers:&lt;br /&gt;
                self._reply_query(process, message)&lt;br /&gt;
            else:&lt;br /&gt;
                self._print(process, message)&lt;br /&gt;
&lt;br /&gt;
    def _print(self, sender, message):&lt;br /&gt;
        h = hash(message.text)&lt;br /&gt;
&lt;br /&gt;
        if h not in self._printed and not self._printed_from_peers(message):&lt;br /&gt;
            self._printed.append(h)&lt;br /&gt;
            print(message.text)&lt;br /&gt;
&lt;br /&gt;
    def _reply_query(self, sender, h):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Invoked when the current process receive a &amp;quot;query&amp;quot; from a peer process.&lt;br /&gt;
        `h` contains the hash of a message which may or may have not been&lt;br /&gt;
        sent from this process; if it was sent, the reply is `Yes`, otherwise `No`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        reply = &amp;quot;Yes&amp;quot; if int(h) in self._printed else &amp;quot;No&amp;quot;&lt;br /&gt;
        asend(sender, reply)&lt;br /&gt;
&lt;br /&gt;
    def _printed_from_peers(self, message):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `True` if this message has already been printed from any of the&lt;br /&gt;
        peer processes, `False` otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        h = hash(message)&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            asend(p, str(h))&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            _, reply = areceive(p)&lt;br /&gt;
&lt;br /&gt;
            if reply.text == &amp;quot;Yes&amp;quot;:&lt;br /&gt;
                return True&lt;br /&gt;
            else if reply.text != &amp;quot;No&amp;quot;:&lt;br /&gt;
                # If the response is neither &amp;quot;Yes&amp;quot; nor &amp;quot;No&amp;quot;, then we have got a query&lt;br /&gt;
                self._reply_query(p, reply)&lt;br /&gt;
&lt;br /&gt;
        return False&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Sulla base dei valori in entrata, è possibile costruire le matrici Allocation (q.tà di risorse allocate per processo e per tipo), Need (q.tà di risorse che ogni processo potrebbe ancora chiedere) e il vettore Available (num. di risorse correntemente disponibili).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left&amp;quot;&lt;br /&gt;
! colspan=3 | Allocation&lt;br /&gt;
|-&lt;br /&gt;
   !   !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 4 || 5&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 3 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 2 || 4&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=3 | Need&lt;br /&gt;
|-&lt;br /&gt;
   !    !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 6 || 8&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 6 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 6 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=2 | Available&lt;br /&gt;
|-&lt;br /&gt;
   ! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | x || y&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nel caso delle risorse di tipo A, deve aversi x &amp;gt;= 6 in quanto un processo dovrà essere selezionato come primo nella permutazione dell'algoritmo del banchiere multivaluta, e tutti quelli correnti hanno lo stesso valore Need(i)(1); per ciò che riguarda le risorse di tipo B, possiamo ragionare per esaustione&lt;br /&gt;
&lt;br /&gt;
* Se il primo processo della permutazione è p1, allora y &amp;gt;= 8 (con questo valore posso soddisfare la richiesta di p1 e in seguito tutte le altre)&lt;br /&gt;
* Se il primo processo della permutazione è p2, allora y &amp;gt;= 5: con questo valore è possibile soddisfare la richiesta di p2; una volta che esso avrà finito, restituirà 3 unità della risorsa B, che permetteranno di soddisfare sia le richieste di A sia quelle di C&lt;br /&gt;
* Se il primo processo della permutazione è p3, allora y &amp;gt;= 8 (ragionamento analogo come per p1)&lt;br /&gt;
&lt;br /&gt;
Volendo scegliere il minimo, y &amp;gt;= 5, ed in conclusione (x, y) &amp;gt;= (6, 5).&lt;br /&gt;
&lt;br /&gt;
''Svolgimento basato in parte sull'approccio di Operating System Concepts di Silberschatz. et al, 9th edition, cap. 7.''&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# Può accadere che il sistema torni in uno stato di safety o che invece porti a deadlock. Diversamente uno stato di safety non può portare direttamente ad uno stato di deadlock, ma solo ad uno di non-safety.&lt;br /&gt;
# Selezionare uno o più tra i processi attivi e sospenderli, salvando il loro stato su memoria secondaria operando delle operazioni di swap-out, finché l'insieme dei frame nella memoria centrale non è in grado di soddisfare tutti i processi rimasti attivi.&lt;br /&gt;
# La scelta è determinata perlopiù dal fattore costo. Con un sistema RAID 1 è possibile ripristinare un disco guasto molto brevemente, in quanto le operazioni coinvolte prevedono una semplice ricopiatura dal disco di backup; con un sistema RAID 5 il ripristino del disco guasto deve coinvolgere tutti i dischi dell'intero array, e ciò può richiedere anche ore per dischi di grandi dimensioni. D'altra parte RAID 1 è più costoso (con n dischi, posso memorizzare tanta informazione quanto potrei con n / 2 dischi) rispetto a RAID 5 dove, tra gli n dischi, complessivamente soltanto uno è destinato alle informazioni di ridondanza.&lt;br /&gt;
# ''Completare.''&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;
        entry 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;
        entry 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;
        entry 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;
&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;
si, è possibile: &lt;br /&gt;
&lt;br /&gt;
Implementare asend e arecv date bsend e brecv&lt;br /&gt;
&lt;br /&gt;
asend(pid_t, msg_type msg){&lt;br /&gt;
    bsend (&amp;lt;pid_t dst, msg&amp;gt;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
arecv(*){&lt;br /&gt;
  pid_t act = getpid(); \\ act = proprio pid &lt;br /&gt;
  do{&lt;br /&gt;
    &amp;lt;dst, msg&amp;gt; = brecv(*);&lt;br /&gt;
  }while (dst =! act)&lt;br /&gt;
  return msg;&lt;br /&gt;
}&lt;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;
entry 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;
entry 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;
entry 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;
monitor altcolbb {&lt;br /&gt;
&lt;br /&gt;
  generic_type valueBuf[MAX];&lt;br /&gt;
  int front = rear = 0;&lt;br /&gt;
&lt;br /&gt;
  bool isFull = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write[2]; //gli indici sono i colori (red=0, blue=1)&lt;br /&gt;
&lt;br /&gt;
  lastColor = None;&lt;br /&gt;
&lt;br /&gt;
  entry void write(color_t color, generic_type val) {&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
        if(isFull)&lt;br /&gt;
          ok2write[color].wait();&lt;br /&gt;
    else&lt;br /&gt;
      if (lastColor == color)&lt;br /&gt;
        ok2write[color].wait();&lt;br /&gt;
              &lt;br /&gt;
    valueBuf[front] = val;&lt;br /&gt;
    front = (front+1) % MAX;&lt;br /&gt;
    lastColor = color;&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
      isFull = true;&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-color].signal();&lt;br /&gt;
&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
        &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry generic_type read(void) {&lt;br /&gt;
&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      if (!isFull)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
&lt;br /&gt;
    generic_type tmpValue = valueBuf[rear];&lt;br /&gt;
    &lt;br /&gt;
    rear = (rear + 1) % MAX;&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      isFull = false;&lt;br /&gt;
      color_t tmpColor = lastColor;&lt;br /&gt;
      lastColor = None;&lt;br /&gt;
      ok2write[tmpColor].signal();  //quando un lettore legge l'ultimo elemento&lt;br /&gt;
                                    //dal buffer, ci possono solo essere scrittori&lt;br /&gt;
                                    //in attesa che abbiano lo stesso colore&lt;br /&gt;
                                    //dell'ultimo elemento.&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-lastColor].signal();&lt;br /&gt;
      &lt;br /&gt;
    return tmpValue;&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;
&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 c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
Il programma dispone di una mutex per l'accesso protetto alla variabile n, e dei due semafori s1 ed s2 per regolare l'alternanza tra i thread A e AB. Sulla base di essi, e del fatto che entrambi i thread eseguono 2 cicli, è possibile affermare (verificare) che&lt;br /&gt;
&lt;br /&gt;
* L'alternanza dei due thread è A-AB-A-AB o&lt;br /&gt;
* L'alternanza dei due thread è AB-A-AB-A&lt;br /&gt;
&lt;br /&gt;
Infatti se il thread A svolgesse due cicli consecutivamente, invocherebbe s1.P() due volte senza fare mai ricorso a s1.V() (ragionamento analogo per AB); pertanto è necessario attendere l'intervento dell'altro thread in attesa di una chiamata su s1.V().&lt;br /&gt;
&lt;br /&gt;
Per concludere, i possibili valori di n al termine del programma saranno, in corrispondenza delle due diramazioni elencate sopra&lt;br /&gt;
&lt;br /&gt;
* n = 12&lt;br /&gt;
* n = 5&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente [[User:Acsor|Acsor]] in data 23/08/2020. Ritengo sia: corretto&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&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;
==== Punto b) ====&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;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
# Frammentazione interna: allocazioni di pagine la cui dimensione è strettamente maggiore di quella effettivamente richiesta.  Frammentazione esterna: nessuno. Infatti ogni spazio (pagina) allocato e liberato è prima o poi riallocato.&lt;br /&gt;
# Se non viene utilizzato un sistema di caching, una lettura diretta a più blocchi di un file di grandi dimensioni richiede: la lettura della FAT, solitamente posta all'inizio di un [[Glossario#Volume|volume]] (e dunque, su dischi rotazionali, in una traccia differente da quella attuale o da quella del blocco da leggere); la lettura del blocco stesso, e dunque lo spostamento della testina nella traccia e nel settore di interesse&lt;br /&gt;
# Uno scheduling a priorità statica può essere utile ad un processo interattivo, dove è necessario mantenersi all'interno di date soglie temporali o semplicemente svolgere un dato compito con meno ritardo possibile; esempi concreti: un processo che faccia streaming video; un processo appartenente ad un server il cui obiettivo primario è soddisfare le richieste dei propri client il prima possibile, ma dove può anche essere svolta qualche attività dai processi locali (es. programmi applicativi). In uno scheduling a priorità statica, se la presenza di processi ad alte priorità è costante, possono verificarsi indesiderati fenomeni di ''starvation'' nei confronti di processi meno prioritari.&lt;br /&gt;
# ''Domanda puramente nozionistica, la cui risposta può essere ricavata consultando note, lucidi o libri di testo.''&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&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;
    if (buffer.lenght() &amp;gt;= MAX) {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX) {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&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;
    generic_type val;&lt;br /&gt;
&lt;br /&gt;
    if (buffer.lenght() == 0) {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&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;
&lt;br /&gt;
    val = buffer.length() == 0 ? NULL: buffer.dequeue();&lt;br /&gt;
    ok2write.signal();&lt;br /&gt;
&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 ===&lt;br /&gt;
&lt;br /&gt;
* Controllato e corretto dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&lt;br /&gt;
===== Algoritmo MIN =====&lt;br /&gt;
&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;
===== Algoritmo 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;
==== Punto b) ====&lt;br /&gt;
&lt;br /&gt;
Poiché non è specificato quale dei due algoritmi precedenti applicare, sono state considerate soluzioni per ognuno di essi&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo MIN (da controllare) =====&lt;br /&gt;
(È possibile ottenere una stringa più breve?)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
4 3 2 1 5 3 2 1 4 5 3 2 1 3 2 4 5 1 2 4 3 1 5 4 2 1 3 4   &lt;br /&gt;
-------------------------------------------------------&lt;br /&gt;
4|4|4|4|5|  5  |5|  5  |1|  1  |1|  1  |1|  1  |   1   &lt;br /&gt;
 |3|3|3|3|  3  |3|  3  |3|  3  |5|  5  |5|  5  |   2   &lt;br /&gt;
 | |2|2|2|  2  |2|  2  |2|  2  |2|  2  |3|  3  |   3   &lt;br /&gt;
 | | |1|1|  1  |4|  4  |4|  4  |4|  4  |4|  4  |   4   &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo LRU =====&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 1 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 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 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;br /&gt;
&lt;br /&gt;
== Esame Pratico 22/01/2016 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2016.01.22.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dirent.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef struct nameNumber {&lt;br /&gt;
        char *name;&lt;br /&gt;
        int value;&lt;br /&gt;
    } nameNumber;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int prefixToInt (char *string) {&lt;br /&gt;
&lt;br /&gt;
    int i = 0;&lt;br /&gt;
    int num = 0;&lt;br /&gt;
    while (string[i] &amp;gt;= '0' &amp;amp;&amp;amp; string[i] &amp;lt; '9' &amp;amp;&amp;amp; i &amp;lt; strlen(string)) {&lt;br /&gt;
        num = (num*10) + (string[i]-'0');&lt;br /&gt;
        i++;&lt;br /&gt;
    }&lt;br /&gt;
    return num;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void fileSort(struct nameNumber **files) {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int comp (const void * el1, const void * el2) {&lt;br /&gt;
    struct nameNumber *f = *((nameNumber**)el1);&lt;br /&gt;
    struct nameNumber *s = *((nameNumber**)el2);&lt;br /&gt;
    if (f-&amp;gt;value &amp;gt; s-&amp;gt;value) return 1;&lt;br /&gt;
    if (f-&amp;gt;value &amp;lt; s-&amp;gt;value) return -1;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int arg, char* argv[]) {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    struct nameNumber **files;&lt;br /&gt;
&lt;br /&gt;
    DIR *dir;&lt;br /&gt;
    struct dirent *ent;&lt;br /&gt;
&lt;br /&gt;
    int count = 0;&lt;br /&gt;
&lt;br /&gt;
    if((dir = opendir(argv[1])) != NULL) &lt;br /&gt;
    {&lt;br /&gt;
        while( (ent = readdir(dir)) != NULL ) &lt;br /&gt;
        {   &lt;br /&gt;
            if (ent-&amp;gt;d_name[0] &amp;lt; '9' &amp;amp;&amp;amp; ent-&amp;gt;d_name[0] &amp;gt;= '0') &lt;br /&gt;
            {&lt;br /&gt;
                files = (struct nameNumber**)realloc(files , (count+1) * sizeof(struct nameNumber*));&lt;br /&gt;
                files[count] = (struct nameNumber*)malloc(sizeof(struct nameNumber));&lt;br /&gt;
                files[count]-&amp;gt;name = (char*)malloc(sizeof(char)*strlen(ent-&amp;gt;d_name) + 1);&lt;br /&gt;
                strcpy(files[count]-&amp;gt;name, ent-&amp;gt;d_name);&lt;br /&gt;
                files[count]-&amp;gt;value = prefixToInt(files[count]-&amp;gt;name);&lt;br /&gt;
                printf(&amp;quot;name : %s  ,  value : %d\n&amp;quot;, files[count]-&amp;gt;name , files[count]-&amp;gt;value);&lt;br /&gt;
                count++;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    qsort(files, count, sizeof(nameNumber*), comp);&lt;br /&gt;
&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i=0; i &amp;lt; count; i++) {&lt;br /&gt;
        printf(&amp;quot;%s\n&amp;quot;,files[i]-&amp;gt;name);&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;
&lt;br /&gt;
== Esame di Concorrenza del 13/01/2005 ==&lt;br /&gt;
Il testo degli esercizi è disponibile alla pagina http://www.cs.unibo.it/~renzo/so/compiti/2005-01-13.con.pdf.&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
Il codice di questo esercizio può essere eseguito scaricando il sorgente Python e l'archivio relativo agli [[Tool_per_semafori_e_monitor|strumenti di concorrenza per il linguaggio Python]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
import threading&lt;br /&gt;
import random&lt;br /&gt;
import time&lt;br /&gt;
from pysm.semaphore import semaphore&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class mod_counter:&lt;br /&gt;
    def __init__(self, mod, start=0):&lt;br /&gt;
        self._mod = mod&lt;br /&gt;
        self._val = start&lt;br /&gt;
&lt;br /&gt;
    def inc(self):&lt;br /&gt;
        self._val = (self._val + 1) % self._mod&lt;br /&gt;
&lt;br /&gt;
    def get(self):&lt;br /&gt;
        return self._val&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class process(threading.Thread):&lt;br /&gt;
    def __init__(self, to_print, c: mod_counter, a, t, r):&lt;br /&gt;
        threading.Thread.__init__(self, name=&amp;quot;proc&amp;quot; + to_print)&lt;br /&gt;
&lt;br /&gt;
        if to_print not in &amp;quot;tar&amp;quot;:&lt;br /&gt;
            raise ValueError(&amp;quot;Unexpected printable character:&amp;quot;, to_print)&lt;br /&gt;
&lt;br /&gt;
        self._counter = c&lt;br /&gt;
        self._x = to_print&lt;br /&gt;
        self._semaphores = {'t': t, 'a': a, 'r': r}&lt;br /&gt;
        self._enter = True&lt;br /&gt;
&lt;br /&gt;
        if self._x == 't':&lt;br /&gt;
            self._semaphores[self._x].V()&lt;br /&gt;
&lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            self.sync()&lt;br /&gt;
            print(&amp;quot;[%s] %c&amp;quot; % (self.name, self._x))&lt;br /&gt;
&lt;br /&gt;
            # Print a trailing newline&lt;br /&gt;
            if (self._counter.get() == 7):&lt;br /&gt;
                print()&lt;br /&gt;
&lt;br /&gt;
            time.sleep(random.random() * 0.5)&lt;br /&gt;
&lt;br /&gt;
    def sync(self):&lt;br /&gt;
        if (self._enter):&lt;br /&gt;
            self._semaphores[self._x].P()&lt;br /&gt;
            self._enter = False&lt;br /&gt;
        else:&lt;br /&gt;
            self._counter.inc()&lt;br /&gt;
            curr = &amp;quot;taratata&amp;quot;[self._counter.get()]&lt;br /&gt;
&lt;br /&gt;
            self._semaphores[curr].V()&lt;br /&gt;
&lt;br /&gt;
            self._enter = True&lt;br /&gt;
            self.sync()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    counter = mod_counter(8)&lt;br /&gt;
    semaphores = (semaphore(0), semaphore(0), semaphore(0))&lt;br /&gt;
    procs = [process(c, counter, *semaphores) for c in &amp;quot;tar&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.daemon = True&lt;br /&gt;
        p.start()&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2570</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=2570"/>
		<updated>2020-08-27T19:01:33Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Svolto es g.2 dell'esame del 12/02/2018&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina raccoglie prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review. Chiunque prenda visione di un esercizio è pregato (per il bene collettivo) a lasciare una [https://www.mediawiki.org/wiki/Help:Signatures propria firma] con nome utente e data di visualizzazione indicando se lo svolgimento è ritenuto corretto; in caso di svolgimento scorretto è invece invitato ad apportare una correzione, lasciando come nel caso precedente il proprio nome utente e data di correzione.&lt;br /&gt;
&lt;br /&gt;
Al fine di verificare la correttezza degli esercizi di concorrenza, segnaliamo la presenza di [[Tool_per_semafori_e_monitor|strumenti di programmazione concorrente]] per i linguaggi C e Python.&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&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 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente Lusvelt in data 26/08/2020 (sbagliato, dal testo si evince che se manca anche solo un componente bisogna mettersi in attesa finchè non arrivi, per poi prendere anche gli altri).&lt;br /&gt;
:: E non è quel che già accade nel ramo else di get()? C'è una wait() ed essa è invocata proprio quando components[i] &amp;gt; self._v[i]. (La chat in Wiki è scomoda, sentiamoci su Telegram.) -- [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:32, 26 August 2020 (CEST)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
    altri operai in attesa.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (possibile soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&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 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Nello pseudocodice seguente, il termine this fa riferimento al processo corrente, mentre ANY ad uno qualunque.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack&amp;lt;message&amp;gt; messages;&lt;br /&gt;
&lt;br /&gt;
void lifo_send(string m, process dest) {&lt;br /&gt;
	do {&lt;br /&gt;
		asend(m, dest);&lt;br /&gt;
	} while (areceive(dest).text != &amp;quot;ACK&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
message lifo_receive(process source) {&lt;br /&gt;
	if (source != ANY) {&lt;br /&gt;
		message m = areceive(source);&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;ACK&amp;quot;, source);&lt;br /&gt;
&lt;br /&gt;
		return m;&lt;br /&gt;
	} else {&lt;br /&gt;
		message m;&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;END&amp;quot;, this);&lt;br /&gt;
		m = areceive(ANY);&lt;br /&gt;
&lt;br /&gt;
		while (m.text != &amp;quot;END&amp;quot; || m.sender != this) {&lt;br /&gt;
			messages.push(m);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                /* Bisogna tenere conto dei casi in cui lifo_receive() viene invocata quando nessun&lt;br /&gt;
                 * messaggio è stato ancora spedito da altri processi. In tal caso si attende il&lt;br /&gt;
                 * il primo e lo si restituisce.&lt;br /&gt;
                 */&lt;br /&gt;
		if (messages.empty()) {&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			return m;&lt;br /&gt;
		} else {&lt;br /&gt;
			return messages.pop();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&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;
* Visto e corretto dall'utente [[User:Acsor|Acsor]] in data 23/08/2020&lt;br /&gt;
* Visto e corretto dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
class LIFOBuffer {&lt;br /&gt;
	stack&amp;lt;T&amp;gt; s;&lt;br /&gt;
	semaphore mutex(1); // mutua esclusione&lt;br /&gt;
	semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
	void push (T value) {&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		s.push(value);&lt;br /&gt;
                // (1)&lt;br /&gt;
		mutex.V()&lt;br /&gt;
&lt;br /&gt;
		ok2consume.V()  // Curiosità: che succede se spostiamo quest'istruzione in (1)?&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	T pop () {&lt;br /&gt;
		T value;&lt;br /&gt;
&lt;br /&gt;
		ok2consume.P();&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		value = s.pop();&lt;br /&gt;
		mutex.V();&lt;br /&gt;
&lt;br /&gt;
		return value;&lt;br /&gt;
	}&lt;br /&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;
# In sistemi dove dispositivi di archiviazione o supporti hardware per la memoria virtuale (e dunque per la paginazione, spesso utilizzata per realizzare il supporto di memoria virtuale) non sono presenti (es. sistemi embedded). ''(In sistemi real-time la memoria virtuale è praticabile? Annotare.)''&lt;br /&gt;
# 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.&lt;br /&gt;
# Per fornire parallelismo e ridondanza. Non è necessario fare backup dei dati sul disco, nel senso di mantenere una copia identica di dati già memorizzati altrove, in quanto diversi sistemi di codici permettono il rilevamento e/o la correzione di errori.&lt;br /&gt;
# Se in un grafo di Holt multirisorsa esiste un ciclo tra più processi e risorse, ciò non significa che allo stesso tempo non siano coinvolti processi con archi esclusivamente entranti. Ogni processo appartenente a questa categoria non è in attesa di risorse, e può dunque procedere con i suoi calcoli; quando avrà terminato rilascerà le risorse precedentemente allocategli, eventualmente sbloccando uno dei processi coinvolti nel ciclo.&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;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
proc[x]: x='a',...,'z'&lt;br /&gt;
 while True:&lt;br /&gt;
  //c sarà il carattere stampato dal processo precedente&lt;br /&gt;
  (c, string) = arecv(*)&lt;br /&gt;
  if(string == wait){&lt;br /&gt;
    //mi metto in attesa di ricevere l'ACK da proc[x]&lt;br /&gt;
    m=arecv(x);&lt;br /&gt;
  }&lt;br /&gt;
  if (c == NONE){&lt;br /&gt;
    //significa che sei il primo a ricevere quella stringa&lt;br /&gt;
    print(x);&lt;br /&gt;
    if (len(string) &amp;gt; 1){&lt;br /&gt;
      //mando la wait a tutti, il primo che riceve qualcosa da stampare manda una wait a tutti&lt;br /&gt;
      asend(wait,*);&lt;br /&gt;
      int l = len(string);&lt;br /&gt;
      int i = 1;&lt;br /&gt;
      while(l != 0){&lt;br /&gt;
        asend(proc[string[i]], (x, string[i...]));&lt;br /&gt;
        //si mette in attesa di ricevere l'ACK dal processo dell'ultima lettera della parola&lt;br /&gt;
        m=areceive(proc[string[i]]);&lt;br /&gt;
        //rimando la wait al processo per ribloccarlo&lt;br /&gt;
        asend(wait, proc[string[i]])&lt;br /&gt;
        l--;&lt;br /&gt;
        i++;&lt;br /&gt;
      }&lt;br /&gt;
      //dopo aver finito la stampa della stringa sblocco tutti i processi&lt;br /&gt;
      asend(ACK, *);&lt;br /&gt;
    }&lt;br /&gt;
  }else{&lt;br /&gt;
    print(x);&lt;br /&gt;
    asend(ACK, x);&lt;br /&gt;
    //ricomincia il ciclo while, si rimette in attesa e il 'gestore gli rimanda la wait'&lt;br /&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;
&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;
&lt;br /&gt;
monitor bridge:&lt;br /&gt;
&lt;br /&gt;
    int ncar&lt;br /&gt;
    bool boat_on_0&lt;br /&gt;
    bool boat_on_1       // per semplicità, quando nel codice si trova boat_on_(direction) oppure isBoat(direction)(),&lt;br /&gt;
                         // si valuta il valore booleano di direction e lo si applica sotto forma di stringa al simbolo&lt;br /&gt;
                         // ad esso adiacente&lt;br /&gt;
    bool is_raised&lt;br /&gt;
    queue waiting_mean   // i valori possibili sono: boat0, boat1 oppure car&lt;br /&gt;
    condition ok2go&lt;br /&gt;
  &lt;br /&gt;
    entry car_enter(direction): &lt;br /&gt;
        if is_raised || ncar == MAXCAR:&lt;br /&gt;
            waiting_mean.enqueue(car)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        is_raised = false&lt;br /&gt;
        ++ncar&lt;br /&gt;
  &lt;br /&gt;
    entry car_exit(direction):&lt;br /&gt;
        --ncar&lt;br /&gt;
        if (waiting_mean.top().isBoat() &amp;amp;&amp;amp; ncar == 0) || waiting_mean.top().isCar():    // isBoat ritorna true se l'oggetto su cui&lt;br /&gt;
            waiting_mean.dequeue()                                                      // è invocata è boat0 oppure boat1&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
  &lt;br /&gt;
    entry boat_enter(direction):&lt;br /&gt;
        if !is_raised || boat_on_(direction):&lt;br /&gt;
            waiting_mean.enqueue(boat)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        if waiting_mean.top().isBoat(!direction)():&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
        is_raised = true&lt;br /&gt;
        boat_on_(direction) = true&lt;br /&gt;
  &lt;br /&gt;
    entry boat_exit(direction):&lt;br /&gt;
        boat_on_(direction) = false&lt;br /&gt;
        if !boat_on_(!direction):&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
&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;
=== 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;
entry 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;
entry 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;
entry 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;
entry 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 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge {&lt;br /&gt;
&lt;br /&gt;
  UP=0;&lt;br /&gt;
  DOWN=1;&lt;br /&gt;
  bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
  bool carAreExiting = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2drive;&lt;br /&gt;
  condition ok2barca[2];&lt;br /&gt;
&lt;br /&gt;
  waitingCar = 0;&lt;br /&gt;
  carOnBridge = 0;&lt;br /&gt;
&lt;br /&gt;
  boatWaiting[2] = {0,0};&lt;br /&gt;
  boatIsPassing[2] = {false,false}&lt;br /&gt;
&lt;br /&gt;
  entry car_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == DOWN)&lt;br /&gt;
      if(carOnBridge == MAXCAR)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
      else if (carAreExiting)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
    else &lt;br /&gt;
      if (boatIsPassing[0] || boatIsPassing[1])&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
    carOnBridge++;&lt;br /&gt;
    carAreExiting = false;&lt;br /&gt;
    if(carOnBridge &amp;lt; MAXCAR &amp;amp;&amp;amp; !carAreExiting) &lt;br /&gt;
      ok2drive.signal();&lt;br /&gt;
      &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry car_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    carOnBridge--;&lt;br /&gt;
    carAreExiting = true;&lt;br /&gt;
&lt;br /&gt;
    if(carOnBridge == 0)&lt;br /&gt;
      carAreExiting = false;&lt;br /&gt;
      if(boatWaiting[0] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[0].signal();&lt;br /&gt;
      else if (boatWaiting[1] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[1].signal();&lt;br /&gt;
      else &lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == UP)&lt;br /&gt;
    | if (boatIsPassing[direction] == true)&lt;br /&gt;
    | |  boatWaiting[direction]++;&lt;br /&gt;
    | |  ok2barca.wait();&lt;br /&gt;
    | |  boatWaiting[direction]--;&lt;br /&gt;
    else &lt;br /&gt;
    | if (carOnBridge &amp;gt; 0)&lt;br /&gt;
    | | boatWaiting[direction]++;&lt;br /&gt;
    | | ok2barca.wait();&lt;br /&gt;
    | | boatWaiting[direction]--;&lt;br /&gt;
    | | bridgeis = UP;&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = true;&lt;br /&gt;
&lt;br /&gt;
    if(boatIsPassing[1-direction] == false &amp;amp;&amp;amp; boatWaiting[1-direction] &amp;gt; 0)&lt;br /&gt;
      ok2barca[1-direction].signal();&lt;br /&gt;
    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = false;&lt;br /&gt;
&lt;br /&gt;
    if (boatIsPassing[1-direction] == false)&lt;br /&gt;
      if (waitingCar &amp;gt; 0)&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
    else&lt;br /&gt;
        if (waitingCar == 0)&lt;br /&gt;
          ok2barca[direction].signal();&lt;br /&gt;
          &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&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;
entry 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;
entry 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;
entry 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;
entry 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;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
list printed_msg;  # questa è una variabile condivisa che ai fini dell'esercizio non si può utilizzare (message passing)&lt;br /&gt;
&lt;br /&gt;
process server[i]:&lt;br /&gt;
  while true:&lt;br /&gt;
    &amp;lt;msg, pid&amp;gt; = arecv(*)&lt;br /&gt;
    if printed_msg.length == 0 or &amp;lt;msg, pid&amp;gt; is not in printed_msg:&lt;br /&gt;
      printed_msg.append(&amp;lt;msg,id&amp;gt;)&lt;br /&gt;
      print(msg)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
Nello svolgimento seguente, receiver incapsula l'ambiente privato del processo; _peers rappresenta il vettore di processi &amp;quot;fratelli&amp;quot; ai quali può essere chiesto di stampare un messaggio, mentre _printed contiene l'hash di tutti i messaggi stampati dal processo locale. Si suppone che istanze della classe receiver possano essere passate come parametro ad areceive() ed asend() (non implementate).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class receiver:&lt;br /&gt;
    def __init__(self, peers):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param peers: list of processes this process communicates with.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self._peers = tuple(peers)&lt;br /&gt;
        self._printed = list()&lt;br /&gt;
    &lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            process, message = areceive(ANY)&lt;br /&gt;
&lt;br /&gt;
            if process in self._peers:&lt;br /&gt;
                self._reply_query(process, message)&lt;br /&gt;
            else:&lt;br /&gt;
                self._print(process, message)&lt;br /&gt;
&lt;br /&gt;
    def _print(self, sender, message):&lt;br /&gt;
        h = hash(message.text)&lt;br /&gt;
&lt;br /&gt;
        if h not in self._printed and not self._printed_from_peers(message):&lt;br /&gt;
            self._printed.append(h)&lt;br /&gt;
            print(message.text)&lt;br /&gt;
&lt;br /&gt;
    def _reply_query(self, sender, h):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Invoked when the current process receive a &amp;quot;query&amp;quot; from a peer process.&lt;br /&gt;
        `h` contains the hash of a message which may or may have not been&lt;br /&gt;
        sent from this process; if it was sent, the reply is `Yes`, otherwise `No`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        reply = &amp;quot;Yes&amp;quot; if int(h) in self._printed else &amp;quot;No&amp;quot;&lt;br /&gt;
        asend(sender, reply)&lt;br /&gt;
&lt;br /&gt;
    def _printed_from_peers(self, message):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `True` if this message has already been printed from any of the&lt;br /&gt;
        peer processes, `False` otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        h = hash(message)&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            asend(p, str(h))&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            _, reply = areceive(p)&lt;br /&gt;
&lt;br /&gt;
            if reply.text == &amp;quot;Yes&amp;quot;:&lt;br /&gt;
                return True&lt;br /&gt;
            else if reply.text != &amp;quot;No&amp;quot;:&lt;br /&gt;
                # If the response is neither &amp;quot;Yes&amp;quot; nor &amp;quot;No&amp;quot;, then we have got a query&lt;br /&gt;
                self._reply_query(p, reply)&lt;br /&gt;
&lt;br /&gt;
        return False&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Sulla base dei valori in entrata, è possibile costruire le matrici Allocation (q.tà di risorse allocate per processo e per tipo), Need (q.tà di risorse che ogni processo potrebbe ancora chiedere) e il vettore Available (num. di risorse correntemente disponibili).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left&amp;quot;&lt;br /&gt;
! colspan=3 | Allocation&lt;br /&gt;
|-&lt;br /&gt;
   !   !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 4 || 5&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 3 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 2 || 4&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=3 | Need&lt;br /&gt;
|-&lt;br /&gt;
   !    !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 6 || 8&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 6 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 6 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=2 | Available&lt;br /&gt;
|-&lt;br /&gt;
   ! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | x || y&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nel caso delle risorse di tipo A, deve aversi x &amp;gt;= 6 in quanto un processo dovrà essere selezionato come primo nella permutazione dell'algoritmo del banchiere multivaluta, e tutti quelli correnti hanno lo stesso valore Need(i)(1); per ciò che riguarda le risorse di tipo B, possiamo ragionare per esaustione&lt;br /&gt;
&lt;br /&gt;
* Se il primo processo della permutazione è p1, allora y &amp;gt;= 8 (con questo valore posso soddisfare la richiesta di p1 e in seguito tutte le altre)&lt;br /&gt;
* Se il primo processo della permutazione è p2, allora y &amp;gt;= 5: con questo valore è possibile soddisfare la richiesta di p2; una volta che esso avrà finito, restituirà 3 unità della risorsa B, che permetteranno di soddisfare sia le richieste di A sia quelle di C&lt;br /&gt;
* Se il primo processo della permutazione è p3, allora y &amp;gt;= 8 (ragionamento analogo come per p1)&lt;br /&gt;
&lt;br /&gt;
Volendo scegliere il minimo, y &amp;gt;= 5, ed in conclusione (x, y) &amp;gt;= (6, 5).&lt;br /&gt;
&lt;br /&gt;
''Svolgimento basato in parte sull'approccio di Operating System Concepts di Silberschatz. et al, 9th edition, cap. 7.''&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# Può accadere che il sistema torni in uno stato di safety o che invece porti a deadlock. Diversamente uno stato di safety non può portare direttamente ad uno stato di deadlock, ma solo ad uno di non-safety.&lt;br /&gt;
# Selezionare uno o più tra i processi attivi e sospenderli, salvando il loro stato su memoria secondaria operando delle operazioni di swap-out, finché l'insieme dei frame nella memoria centrale non è in grado di soddisfare tutti i processi rimasti attivi.&lt;br /&gt;
# La scelta è determinata perlopiù dal fattore costo. Con un sistema RAID 1 è possibile ripristinare un disco guasto molto brevemente, in quanto le operazioni coinvolte prevedono una semplice ricopiatura dal disco di backup; con un sistema RAID 5 il ripristino del disco guasto deve coinvolgere tutti i dischi dell'intero array, e ciò può richiedere anche ore per dischi di grandi dimensioni. D'altra parte RAID 1 è più costoso (con n dischi, posso memorizzare tanta informazione quanto potrei con n / 2 dischi) rispetto a RAID 5 dove, tra gli n dischi, complessivamente soltanto uno è destinato alle informazioni di ridondanza.&lt;br /&gt;
# ''Completare.''&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;
        entry 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;
        entry 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;
        entry 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;
&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;
si, è possibile: &lt;br /&gt;
&lt;br /&gt;
Implementare asend e arecv date bsend e brecv&lt;br /&gt;
&lt;br /&gt;
asend(pid_t, msg_type msg){&lt;br /&gt;
    bsend (&amp;lt;pid_t dst, msg&amp;gt;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
arecv(*){&lt;br /&gt;
  pid_t act = getpid(); \\ act = proprio pid &lt;br /&gt;
  do{&lt;br /&gt;
    &amp;lt;dst, msg&amp;gt; = brecv(*);&lt;br /&gt;
  }while (dst =! act)&lt;br /&gt;
  return msg;&lt;br /&gt;
}&lt;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;
entry 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;
entry 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;
entry 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;
monitor altcolbb {&lt;br /&gt;
&lt;br /&gt;
  generic_type valueBuf[MAX];&lt;br /&gt;
  int front = rear = 0;&lt;br /&gt;
&lt;br /&gt;
  bool isFull = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write[2]; //gli indici sono i colori (red=0, blue=1)&lt;br /&gt;
&lt;br /&gt;
  lastColor = None;&lt;br /&gt;
&lt;br /&gt;
  entry void write(color_t color, generic_type val) {&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
        if(isFull)&lt;br /&gt;
          ok2write[color].wait();&lt;br /&gt;
    else&lt;br /&gt;
      if (lastColor == color)&lt;br /&gt;
        ok2write[color].wait();&lt;br /&gt;
              &lt;br /&gt;
    valueBuf[front] = val;&lt;br /&gt;
    front = (front+1) % MAX;&lt;br /&gt;
    lastColor = color;&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
      isFull = true;&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-color].signal();&lt;br /&gt;
&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
        &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry generic_type read(void) {&lt;br /&gt;
&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      if (!isFull)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
&lt;br /&gt;
    generic_type tmpValue = valueBuf[rear];&lt;br /&gt;
    &lt;br /&gt;
    rear = (rear + 1) % MAX;&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      isFull = false;&lt;br /&gt;
      color_t tmpColor = lastColor;&lt;br /&gt;
      lastColor = None;&lt;br /&gt;
      ok2write[tmpColor].signal();  //quando un lettore legge l'ultimo elemento&lt;br /&gt;
                                    //dal buffer, ci possono solo essere scrittori&lt;br /&gt;
                                    //in attesa che abbiano lo stesso colore&lt;br /&gt;
                                    //dell'ultimo elemento.&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-lastColor].signal();&lt;br /&gt;
      &lt;br /&gt;
    return tmpValue;&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;
&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 c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
Il programma dispone di una mutex per l'accesso protetto alla variabile n, e dei due semafori s1 ed s2 per regolare l'alternanza tra i thread A e AB. Sulla base di essi, e del fatto che entrambi i thread eseguono 2 cicli, è possibile affermare (verificare) che&lt;br /&gt;
&lt;br /&gt;
* L'alternanza dei due thread è A-AB-A-AB o&lt;br /&gt;
* L'alternanza dei due thread è AB-A-AB-A&lt;br /&gt;
&lt;br /&gt;
Infatti se il thread A svolgesse due cicli consecutivamente, invocherebbe s1.P() due volte senza fare mai ricorso a s1.V() (ragionamento analogo per AB); pertanto è necessario attendere l'intervento dell'altro thread in attesa di una chiamata su s1.V().&lt;br /&gt;
&lt;br /&gt;
Per concludere, i possibili valori di n al termine del programma saranno, in corrispondenza delle due diramazioni elencate sopra&lt;br /&gt;
&lt;br /&gt;
* n = 12&lt;br /&gt;
* n = 5&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente [[User:Acsor|Acsor]] in data 23/08/2020. Ritengo sia: corretto&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&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;
==== Punto b) ====&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;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
# Frammentazione interna: allocazioni di pagine la cui dimensione è strettamente maggiore di quella effettivamente richiesta.  Frammentazione esterna: nessuno. Infatti ogni spazio (pagina) allocato e liberato è prima o poi riallocato.&lt;br /&gt;
# Se non viene utilizzato un sistema di caching, una lettura diretta a più blocchi di un file di grandi dimensioni richiede: la lettura della FAT, solitamente posta all'inizio di un [[Glossario#Volume|volume]] (e dunque, su dischi rotazionali, in una traccia differente da quella attuale o da quella del blocco da leggere); la lettura del blocco stesso, e dunque lo spostamento della testina nella traccia e nel settore di interesse&lt;br /&gt;
# Uno scheduling a priorità statica può essere utile ad un processo interattivo, dove è necessario mantenersi all'interno di date soglie temporali o semplicemente svolgere un dato compito con meno ritardo possibile; esempi concreti: un processo che faccia streaming video; un processo appartenente ad un server il cui obiettivo primario è soddisfare le richieste dei propri client il prima possibile, ma dove può anche essere svolta qualche attività dai processi locali (es. programmi applicativi). In uno scheduling a priorità statica, se la presenza di processi ad alte priorità è costante, possono verificarsi indesiderati fenomeni di ''starvation'' nei confronti di processi meno prioritari.&lt;br /&gt;
# ''Domanda puramente nozionistica, la cui risposta può essere ricavata consultando note, lucidi o libri di testo.''&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&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;
    if (buffer.lenght() &amp;gt;= MAX) {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX) {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&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;
    generic_type val;&lt;br /&gt;
&lt;br /&gt;
    if (buffer.lenght() == 0) {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&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;
&lt;br /&gt;
    val = buffer.length() == 0 ? NULL: buffer.dequeue();&lt;br /&gt;
    ok2write.signal();&lt;br /&gt;
&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 ===&lt;br /&gt;
&lt;br /&gt;
* Controllato e corretto dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&lt;br /&gt;
===== Algoritmo MIN =====&lt;br /&gt;
&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;
===== Algoritmo 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;
==== Punto b) ====&lt;br /&gt;
&lt;br /&gt;
Poiché non è specificato quale dei due algoritmi precedenti applicare, sono state considerate soluzioni per ognuno di essi&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo MIN (da controllare) =====&lt;br /&gt;
(È possibile ottenere una stringa più breve?)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
4 3 2 1 5 3 2 1 4 5 3 2 1 3 2 4 5 1 2 4 3 1 5 4 2 1 3 4   &lt;br /&gt;
-------------------------------------------------------&lt;br /&gt;
4|4|4|4|5|  5  |5|  5  |1|  1  |1|  1  |1|  1  |   1   &lt;br /&gt;
 |3|3|3|3|  3  |3|  3  |3|  3  |5|  5  |5|  5  |   2   &lt;br /&gt;
 | |2|2|2|  2  |2|  2  |2|  2  |2|  2  |3|  3  |   3   &lt;br /&gt;
 | | |1|1|  1  |4|  4  |4|  4  |4|  4  |4|  4  |   4   &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo LRU =====&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 1 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 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 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;br /&gt;
&lt;br /&gt;
== Esame Pratico 22/01/2016 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2016.01.22.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dirent.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef struct nameNumber {&lt;br /&gt;
        char *name;&lt;br /&gt;
        int value;&lt;br /&gt;
    } nameNumber;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int prefixToInt (char *string) {&lt;br /&gt;
&lt;br /&gt;
    int i = 0;&lt;br /&gt;
    int num = 0;&lt;br /&gt;
    while (string[i] &amp;gt;= '0' &amp;amp;&amp;amp; string[i] &amp;lt; '9' &amp;amp;&amp;amp; i &amp;lt; strlen(string)) {&lt;br /&gt;
        num = (num*10) + (string[i]-'0');&lt;br /&gt;
        i++;&lt;br /&gt;
    }&lt;br /&gt;
    return num;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void fileSort(struct nameNumber **files) {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int comp (const void * el1, const void * el2) {&lt;br /&gt;
    struct nameNumber *f = *((nameNumber**)el1);&lt;br /&gt;
    struct nameNumber *s = *((nameNumber**)el2);&lt;br /&gt;
    if (f-&amp;gt;value &amp;gt; s-&amp;gt;value) return 1;&lt;br /&gt;
    if (f-&amp;gt;value &amp;lt; s-&amp;gt;value) return -1;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int arg, char* argv[]) {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    struct nameNumber **files;&lt;br /&gt;
&lt;br /&gt;
    DIR *dir;&lt;br /&gt;
    struct dirent *ent;&lt;br /&gt;
&lt;br /&gt;
    int count = 0;&lt;br /&gt;
&lt;br /&gt;
    if((dir = opendir(argv[1])) != NULL) &lt;br /&gt;
    {&lt;br /&gt;
        while( (ent = readdir(dir)) != NULL ) &lt;br /&gt;
        {   &lt;br /&gt;
            if (ent-&amp;gt;d_name[0] &amp;lt; '9' &amp;amp;&amp;amp; ent-&amp;gt;d_name[0] &amp;gt;= '0') &lt;br /&gt;
            {&lt;br /&gt;
                files = (struct nameNumber**)realloc(files , (count+1) * sizeof(struct nameNumber*));&lt;br /&gt;
                files[count] = (struct nameNumber*)malloc(sizeof(struct nameNumber));&lt;br /&gt;
                files[count]-&amp;gt;name = (char*)malloc(sizeof(char)*strlen(ent-&amp;gt;d_name) + 1);&lt;br /&gt;
                strcpy(files[count]-&amp;gt;name, ent-&amp;gt;d_name);&lt;br /&gt;
                files[count]-&amp;gt;value = prefixToInt(files[count]-&amp;gt;name);&lt;br /&gt;
                printf(&amp;quot;name : %s  ,  value : %d\n&amp;quot;, files[count]-&amp;gt;name , files[count]-&amp;gt;value);&lt;br /&gt;
                count++;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    qsort(files, count, sizeof(nameNumber*), comp);&lt;br /&gt;
&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i=0; i &amp;lt; count; i++) {&lt;br /&gt;
        printf(&amp;quot;%s\n&amp;quot;,files[i]-&amp;gt;name);&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;
&lt;br /&gt;
== Esame di Concorrenza del 13/01/2005 ==&lt;br /&gt;
Il testo degli esercizi è disponibile alla pagina http://www.cs.unibo.it/~renzo/so/compiti/2005-01-13.con.pdf.&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
Il codice di questo esercizio può essere eseguito scaricando il sorgente Python e l'archivio relativo agli [[Tool_per_semafori_e_monitor|strumenti di concorrenza per il linguaggio Python]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
import threading&lt;br /&gt;
import random&lt;br /&gt;
import time&lt;br /&gt;
from pysm.semaphore import semaphore&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class mod_counter:&lt;br /&gt;
    def __init__(self, mod, start=0):&lt;br /&gt;
        self._mod = mod&lt;br /&gt;
        self._val = start&lt;br /&gt;
&lt;br /&gt;
    def inc(self):&lt;br /&gt;
        self._val = (self._val + 1) % self._mod&lt;br /&gt;
&lt;br /&gt;
    def get(self):&lt;br /&gt;
        return self._val&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class process(threading.Thread):&lt;br /&gt;
    def __init__(self, to_print, c: mod_counter, a, t, r):&lt;br /&gt;
        threading.Thread.__init__(self, name=&amp;quot;proc&amp;quot; + to_print)&lt;br /&gt;
&lt;br /&gt;
        if to_print not in &amp;quot;tar&amp;quot;:&lt;br /&gt;
            raise ValueError(&amp;quot;Unexpected printable character:&amp;quot;, to_print)&lt;br /&gt;
&lt;br /&gt;
        self._counter = c&lt;br /&gt;
        self._x = to_print&lt;br /&gt;
        self._semaphores = {'t': t, 'a': a, 'r': r}&lt;br /&gt;
        self._enter = True&lt;br /&gt;
&lt;br /&gt;
        if self._x == 't':&lt;br /&gt;
            self._semaphores[self._x].V()&lt;br /&gt;
&lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            self.sync()&lt;br /&gt;
            print(&amp;quot;[%s] %c&amp;quot; % (self.name, self._x))&lt;br /&gt;
&lt;br /&gt;
            # Print a trailing newline&lt;br /&gt;
            if (self._counter.get() == 7):&lt;br /&gt;
                print()&lt;br /&gt;
&lt;br /&gt;
            time.sleep(random.random() * 0.5)&lt;br /&gt;
&lt;br /&gt;
    def sync(self):&lt;br /&gt;
        if (self._enter):&lt;br /&gt;
            self._semaphores[self._x].P()&lt;br /&gt;
            self._enter = False&lt;br /&gt;
        else:&lt;br /&gt;
            self._counter.inc()&lt;br /&gt;
            curr = &amp;quot;taratata&amp;quot;[self._counter.get()]&lt;br /&gt;
&lt;br /&gt;
            self._semaphores[curr].V()&lt;br /&gt;
&lt;br /&gt;
            self._enter = True&lt;br /&gt;
            self.sync()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    counter = mod_counter(8)&lt;br /&gt;
    semaphores = (semaphore(0), semaphore(0), semaphore(0))&lt;br /&gt;
    procs = [process(c, counter, *semaphores) for c in &amp;quot;tar&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.daemon = True&lt;br /&gt;
        p.start()&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2569</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=2569"/>
		<updated>2020-08-27T18:41:31Z</updated>

		<summary type="html">&lt;p&gt;Acsor: /* Esercizio c.2 (da controllare) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina raccoglie prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review. Chiunque prenda visione di un esercizio è pregato (per il bene collettivo) a lasciare una [https://www.mediawiki.org/wiki/Help:Signatures propria firma] con nome utente e data di visualizzazione indicando se lo svolgimento è ritenuto corretto; in caso di svolgimento scorretto è invece invitato ad apportare una correzione, lasciando come nel caso precedente il proprio nome utente e data di correzione.&lt;br /&gt;
&lt;br /&gt;
Al fine di verificare la correttezza degli esercizi di concorrenza, segnaliamo la presenza di [[Tool_per_semafori_e_monitor|strumenti di programmazione concorrente]] per i linguaggi C e Python.&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&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 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente Lusvelt in data 26/08/2020 (sbagliato, dal testo si evince che se manca anche solo un componente bisogna mettersi in attesa finchè non arrivi, per poi prendere anche gli altri).&lt;br /&gt;
:: E non è quel che già accade nel ramo else di get()? C'è una wait() ed essa è invocata proprio quando components[i] &amp;gt; self._v[i]. (La chat in Wiki è scomoda, sentiamoci su Telegram.) -- [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:32, 26 August 2020 (CEST)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
    altri operai in attesa.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (possibile soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&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 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Nello pseudocodice seguente, il termine this fa riferimento al processo corrente, mentre ANY ad uno qualunque.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack&amp;lt;message&amp;gt; messages;&lt;br /&gt;
&lt;br /&gt;
void lifo_send(string m, process dest) {&lt;br /&gt;
	do {&lt;br /&gt;
		asend(m, dest);&lt;br /&gt;
	} while (areceive(dest).text != &amp;quot;ACK&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
message lifo_receive(process source) {&lt;br /&gt;
	if (source != ANY) {&lt;br /&gt;
		message m = areceive(source);&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;ACK&amp;quot;, source);&lt;br /&gt;
&lt;br /&gt;
		return m;&lt;br /&gt;
	} else {&lt;br /&gt;
		message m;&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;END&amp;quot;, this);&lt;br /&gt;
		m = areceive(ANY);&lt;br /&gt;
&lt;br /&gt;
		while (m.text != &amp;quot;END&amp;quot; || m.sender != this) {&lt;br /&gt;
			messages.push(m);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                /* Bisogna tenere conto dei casi in cui lifo_receive() viene invocata quando nessun&lt;br /&gt;
                 * messaggio è stato ancora spedito da altri processi. In tal caso si attende il&lt;br /&gt;
                 * il primo e lo si restituisce.&lt;br /&gt;
                 */&lt;br /&gt;
		if (messages.empty()) {&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			return m;&lt;br /&gt;
		} else {&lt;br /&gt;
			return messages.pop();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&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;
* Visto e corretto dall'utente [[User:Acsor|Acsor]] in data 23/08/2020&lt;br /&gt;
* Visto e corretto dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
class LIFOBuffer {&lt;br /&gt;
	stack&amp;lt;T&amp;gt; s;&lt;br /&gt;
	semaphore mutex(1); // mutua esclusione&lt;br /&gt;
	semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
	void push (T value) {&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		s.push(value);&lt;br /&gt;
                // (1)&lt;br /&gt;
		mutex.V()&lt;br /&gt;
&lt;br /&gt;
		ok2consume.V()  // Curiosità: che succede se spostiamo quest'istruzione in (1)?&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	T pop () {&lt;br /&gt;
		T value;&lt;br /&gt;
&lt;br /&gt;
		ok2consume.P();&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		value = s.pop();&lt;br /&gt;
		mutex.V();&lt;br /&gt;
&lt;br /&gt;
		return value;&lt;br /&gt;
	}&lt;br /&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;
# In sistemi dove dispositivi di archiviazione o supporti hardware per la memoria virtuale (e dunque per la paginazione, spesso utilizzata per realizzare il supporto di memoria virtuale) non sono presenti (es. sistemi embedded). ''(In sistemi real-time la memoria virtuale è praticabile? Annotare.)''&lt;br /&gt;
# 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.&lt;br /&gt;
# Per fornire parallelismo e ridondanza. Non è necessario fare backup dei dati sul disco, nel senso di mantenere una copia identica di dati già memorizzati altrove, in quanto diversi sistemi di codici permettono il rilevamento e/o la correzione di errori.&lt;br /&gt;
# Se in un grafo di Holt multirisorsa esiste un ciclo tra più processi e risorse, ciò non significa che allo stesso tempo non siano coinvolti processi con archi esclusivamente entranti. Ogni processo appartenente a questa categoria non è in attesa di risorse, e può dunque procedere con i suoi calcoli; quando avrà terminato rilascerà le risorse precedentemente allocategli, eventualmente sbloccando uno dei processi coinvolti nel ciclo.&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;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
proc[x]: x='a',...,'z'&lt;br /&gt;
 while True:&lt;br /&gt;
  //c sarà il carattere stampato dal processo precedente&lt;br /&gt;
  (c, string) = arecv(*)&lt;br /&gt;
  if(string == wait){&lt;br /&gt;
    //mi metto in attesa di ricevere l'ACK da proc[x]&lt;br /&gt;
    m=arecv(x);&lt;br /&gt;
  }&lt;br /&gt;
  if (c == NONE){&lt;br /&gt;
    //significa che sei il primo a ricevere quella stringa&lt;br /&gt;
    print(x);&lt;br /&gt;
    if (len(string) &amp;gt; 1){&lt;br /&gt;
      //mando la wait a tutti, il primo che riceve qualcosa da stampare manda una wait a tutti&lt;br /&gt;
      asend(wait,*);&lt;br /&gt;
      int l = len(string);&lt;br /&gt;
      int i = 1;&lt;br /&gt;
      while(l != 0){&lt;br /&gt;
        asend(proc[string[i]], (x, string[i...]));&lt;br /&gt;
        //si mette in attesa di ricevere l'ACK dal processo dell'ultima lettera della parola&lt;br /&gt;
        m=areceive(proc[string[i]]);&lt;br /&gt;
        //rimando la wait al processo per ribloccarlo&lt;br /&gt;
        asend(wait, proc[string[i]])&lt;br /&gt;
        l--;&lt;br /&gt;
        i++;&lt;br /&gt;
      }&lt;br /&gt;
      //dopo aver finito la stampa della stringa sblocco tutti i processi&lt;br /&gt;
      asend(ACK, *);&lt;br /&gt;
    }&lt;br /&gt;
  }else{&lt;br /&gt;
    print(x);&lt;br /&gt;
    asend(ACK, x);&lt;br /&gt;
    //ricomincia il ciclo while, si rimette in attesa e il 'gestore gli rimanda la wait'&lt;br /&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;
&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;
&lt;br /&gt;
monitor bridge:&lt;br /&gt;
&lt;br /&gt;
    int ncar&lt;br /&gt;
    bool boat_on_0&lt;br /&gt;
    bool boat_on_1       // per semplicità, quando nel codice si trova boat_on_(direction) oppure isBoat(direction)(),&lt;br /&gt;
                         // si valuta il valore booleano di direction e lo si applica sotto forma di stringa al simbolo&lt;br /&gt;
                         // ad esso adiacente&lt;br /&gt;
    bool is_raised&lt;br /&gt;
    queue waiting_mean   // i valori possibili sono: boat0, boat1 oppure car&lt;br /&gt;
    condition ok2go&lt;br /&gt;
  &lt;br /&gt;
    entry car_enter(direction): &lt;br /&gt;
        if is_raised || ncar == MAXCAR:&lt;br /&gt;
            waiting_mean.enqueue(car)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        is_raised = false&lt;br /&gt;
        ++ncar&lt;br /&gt;
  &lt;br /&gt;
    entry car_exit(direction):&lt;br /&gt;
        --ncar&lt;br /&gt;
        if (waiting_mean.top().isBoat() &amp;amp;&amp;amp; ncar == 0) || waiting_mean.top().isCar():    // isBoat ritorna true se l'oggetto su cui&lt;br /&gt;
            waiting_mean.dequeue()                                                      // è invocata è boat0 oppure boat1&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
  &lt;br /&gt;
    entry boat_enter(direction):&lt;br /&gt;
        if !is_raised || boat_on_(direction):&lt;br /&gt;
            waiting_mean.enqueue(boat)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        if waiting_mean.top().isBoat(!direction)():&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
        is_raised = true&lt;br /&gt;
        boat_on_(direction) = true&lt;br /&gt;
  &lt;br /&gt;
    entry boat_exit(direction):&lt;br /&gt;
        boat_on_(direction) = false&lt;br /&gt;
        if !boat_on_(!direction):&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
&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;
=== 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;
entry 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;
entry 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;
entry 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;
entry 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 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge {&lt;br /&gt;
&lt;br /&gt;
  UP=0;&lt;br /&gt;
  DOWN=1;&lt;br /&gt;
  bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
  bool carAreExiting = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2drive;&lt;br /&gt;
  condition ok2barca[2];&lt;br /&gt;
&lt;br /&gt;
  waitingCar = 0;&lt;br /&gt;
  carOnBridge = 0;&lt;br /&gt;
&lt;br /&gt;
  boatWaiting[2] = {0,0};&lt;br /&gt;
  boatIsPassing[2] = {false,false}&lt;br /&gt;
&lt;br /&gt;
  entry car_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == DOWN)&lt;br /&gt;
      if(carOnBridge == MAXCAR)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
      else if (carAreExiting)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
    else &lt;br /&gt;
      if (boatIsPassing[0] || boatIsPassing[1])&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
    carOnBridge++;&lt;br /&gt;
    carAreExiting = false;&lt;br /&gt;
    if(carOnBridge &amp;lt; MAXCAR &amp;amp;&amp;amp; !carAreExiting) &lt;br /&gt;
      ok2drive.signal();&lt;br /&gt;
      &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry car_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    carOnBridge--;&lt;br /&gt;
    carAreExiting = true;&lt;br /&gt;
&lt;br /&gt;
    if(carOnBridge == 0)&lt;br /&gt;
      carAreExiting = false;&lt;br /&gt;
      if(boatWaiting[0] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[0].signal();&lt;br /&gt;
      else if (boatWaiting[1] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[1].signal();&lt;br /&gt;
      else &lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == UP)&lt;br /&gt;
    | if (boatIsPassing[direction] == true)&lt;br /&gt;
    | |  boatWaiting[direction]++;&lt;br /&gt;
    | |  ok2barca.wait();&lt;br /&gt;
    | |  boatWaiting[direction]--;&lt;br /&gt;
    else &lt;br /&gt;
    | if (carOnBridge &amp;gt; 0)&lt;br /&gt;
    | | boatWaiting[direction]++;&lt;br /&gt;
    | | ok2barca.wait();&lt;br /&gt;
    | | boatWaiting[direction]--;&lt;br /&gt;
    | | bridgeis = UP;&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = true;&lt;br /&gt;
&lt;br /&gt;
    if(boatIsPassing[1-direction] == false &amp;amp;&amp;amp; boatWaiting[1-direction] &amp;gt; 0)&lt;br /&gt;
      ok2barca[1-direction].signal();&lt;br /&gt;
    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = false;&lt;br /&gt;
&lt;br /&gt;
    if (boatIsPassing[1-direction] == false)&lt;br /&gt;
      if (waitingCar &amp;gt; 0)&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
    else&lt;br /&gt;
        if (waitingCar == 0)&lt;br /&gt;
          ok2barca[direction].signal();&lt;br /&gt;
          &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&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;
entry 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;
entry 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;
entry 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;
entry 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;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
list printed_msg;  # questa è una variabile condivisa che ai fini dell'esercizio non si può utilizzare (message passing)&lt;br /&gt;
&lt;br /&gt;
process server[i]:&lt;br /&gt;
  while true:&lt;br /&gt;
    &amp;lt;msg, pid&amp;gt; = arecv(*)&lt;br /&gt;
    if printed_msg.length == 0 or &amp;lt;msg, pid&amp;gt; is not in printed_msg:&lt;br /&gt;
      printed_msg.append(&amp;lt;msg,id&amp;gt;)&lt;br /&gt;
      print(msg)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
Nello svolgimento seguente, receiver incapsula l'ambiente privato del processo; _peers rappresenta il vettore di processi &amp;quot;fratelli&amp;quot; ai quali può essere chiesto di stampare un messaggio, mentre _printed contiene l'hash di tutti i messaggi stampati dal processo locale. Si suppone che istanze della classe receiver possano essere passate come parametro ad areceive() ed asend() (non implementate).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class receiver:&lt;br /&gt;
    def __init__(self, peers):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param peers: list of processes this process communicates with.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self._peers = tuple(peers)&lt;br /&gt;
        self._printed = list()&lt;br /&gt;
    &lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            process, message = areceive(ANY)&lt;br /&gt;
&lt;br /&gt;
            if process in self._peers:&lt;br /&gt;
                self._reply_query(process, message)&lt;br /&gt;
            else:&lt;br /&gt;
                self._print(process, message)&lt;br /&gt;
&lt;br /&gt;
    def _print(self, sender, message):&lt;br /&gt;
        h = hash(message.text)&lt;br /&gt;
&lt;br /&gt;
        if h not in self._printed and not self._printed_from_peers(message):&lt;br /&gt;
            self._printed.append(h)&lt;br /&gt;
            print(message.text)&lt;br /&gt;
&lt;br /&gt;
    def _reply_query(self, sender, h):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Invoked when the current process receive a &amp;quot;query&amp;quot; from a peer process.&lt;br /&gt;
        `h` contains the hash of a message which may or may have not been&lt;br /&gt;
        sent from this process; if it was sent, the reply is `Yes`, otherwise `No`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        reply = &amp;quot;Yes&amp;quot; if int(h) in self._printed else &amp;quot;No&amp;quot;&lt;br /&gt;
        asend(sender, reply)&lt;br /&gt;
&lt;br /&gt;
    def _printed_from_peers(self, message):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `True` if this message has already been printed from any of the&lt;br /&gt;
        peer processes, `False` otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        h = hash(message)&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            asend(p, str(h))&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            _, reply = areceive(p)&lt;br /&gt;
&lt;br /&gt;
            if reply.text == &amp;quot;Yes&amp;quot;:&lt;br /&gt;
                return True&lt;br /&gt;
            else if reply.text != &amp;quot;No&amp;quot;:&lt;br /&gt;
                # If the response is neither &amp;quot;Yes&amp;quot; nor &amp;quot;No&amp;quot;, then we have got a query&lt;br /&gt;
                self._reply_query(p, reply)&lt;br /&gt;
&lt;br /&gt;
        return False&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Sulla base dei valori in entrata, è possibile costruire le matrici Allocation (q.tà di risorse allocate per processo e per tipo), Need (q.tà di risorse che ogni processo potrebbe ancora chiedere) e il vettore Available (num. di risorse correntemente disponibili).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left&amp;quot;&lt;br /&gt;
! colspan=3 | Allocation&lt;br /&gt;
|-&lt;br /&gt;
   !   !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 4 || 5&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 3 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 2 || 4&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=3 | Need&lt;br /&gt;
|-&lt;br /&gt;
   !    !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 6 || 8&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 6 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 6 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=2 | Available&lt;br /&gt;
|-&lt;br /&gt;
   ! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | x || y&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nel caso delle risorse di tipo A, deve aversi x &amp;gt;= 6 in quanto un processo dovrà essere selezionato come primo nella permutazione dell'algoritmo del banchiere multivaluta, e tutti quelli correnti hanno lo stesso valore Need(i)(1); per ciò che riguarda le risorse di tipo B, possiamo ragionare per esaustione&lt;br /&gt;
&lt;br /&gt;
* Se il primo processo della permutazione è p1, allora y &amp;gt;= 8 (con questo valore posso soddisfare la richiesta di p1 e in seguito tutte le altre)&lt;br /&gt;
* Se il primo processo della permutazione è p2, allora y &amp;gt;= 5: con questo valore è possibile soddisfare la richiesta di p2; una volta che esso avrà finito, restituirà 3 unità della risorsa B, che permetteranno di soddisfare sia le richieste di A sia quelle di C&lt;br /&gt;
* Se il primo processo della permutazione è p3, allora y &amp;gt;= 8 (ragionamento analogo come per p1)&lt;br /&gt;
&lt;br /&gt;
Volendo scegliere il minimo, y &amp;gt;= 5, ed in conclusione (x, y) &amp;gt;= (6, 5).&lt;br /&gt;
&lt;br /&gt;
''Svolgimento basato in parte sull'approccio di Operating System Concepts di Silberschatz. et al, 9th edition, cap. 7.''&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;
        entry 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;
        entry 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;
        entry 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;
&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;
si, è possibile: &lt;br /&gt;
&lt;br /&gt;
Implementare asend e arecv date bsend e brecv&lt;br /&gt;
&lt;br /&gt;
asend(pid_t, msg_type msg){&lt;br /&gt;
    bsend (&amp;lt;pid_t dst, msg&amp;gt;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
arecv(*){&lt;br /&gt;
  pid_t act = getpid(); \\ act = proprio pid &lt;br /&gt;
  do{&lt;br /&gt;
    &amp;lt;dst, msg&amp;gt; = brecv(*);&lt;br /&gt;
  }while (dst =! act)&lt;br /&gt;
  return msg;&lt;br /&gt;
}&lt;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;
entry 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;
entry 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;
entry 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;
monitor altcolbb {&lt;br /&gt;
&lt;br /&gt;
  generic_type valueBuf[MAX];&lt;br /&gt;
  int front = rear = 0;&lt;br /&gt;
&lt;br /&gt;
  bool isFull = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write[2]; //gli indici sono i colori (red=0, blue=1)&lt;br /&gt;
&lt;br /&gt;
  lastColor = None;&lt;br /&gt;
&lt;br /&gt;
  entry void write(color_t color, generic_type val) {&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
        if(isFull)&lt;br /&gt;
          ok2write[color].wait();&lt;br /&gt;
    else&lt;br /&gt;
      if (lastColor == color)&lt;br /&gt;
        ok2write[color].wait();&lt;br /&gt;
              &lt;br /&gt;
    valueBuf[front] = val;&lt;br /&gt;
    front = (front+1) % MAX;&lt;br /&gt;
    lastColor = color;&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
      isFull = true;&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-color].signal();&lt;br /&gt;
&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
        &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry generic_type read(void) {&lt;br /&gt;
&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      if (!isFull)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
&lt;br /&gt;
    generic_type tmpValue = valueBuf[rear];&lt;br /&gt;
    &lt;br /&gt;
    rear = (rear + 1) % MAX;&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      isFull = false;&lt;br /&gt;
      color_t tmpColor = lastColor;&lt;br /&gt;
      lastColor = None;&lt;br /&gt;
      ok2write[tmpColor].signal();  //quando un lettore legge l'ultimo elemento&lt;br /&gt;
                                    //dal buffer, ci possono solo essere scrittori&lt;br /&gt;
                                    //in attesa che abbiano lo stesso colore&lt;br /&gt;
                                    //dell'ultimo elemento.&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-lastColor].signal();&lt;br /&gt;
      &lt;br /&gt;
    return tmpValue;&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;
&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 c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
Il programma dispone di una mutex per l'accesso protetto alla variabile n, e dei due semafori s1 ed s2 per regolare l'alternanza tra i thread A e AB. Sulla base di essi, e del fatto che entrambi i thread eseguono 2 cicli, è possibile affermare (verificare) che&lt;br /&gt;
&lt;br /&gt;
* L'alternanza dei due thread è A-AB-A-AB o&lt;br /&gt;
* L'alternanza dei due thread è AB-A-AB-A&lt;br /&gt;
&lt;br /&gt;
Infatti se il thread A svolgesse due cicli consecutivamente, invocherebbe s1.P() due volte senza fare mai ricorso a s1.V() (ragionamento analogo per AB); pertanto è necessario attendere l'intervento dell'altro thread in attesa di una chiamata su s1.V().&lt;br /&gt;
&lt;br /&gt;
Per concludere, i possibili valori di n al termine del programma saranno, in corrispondenza delle due diramazioni elencate sopra&lt;br /&gt;
&lt;br /&gt;
* n = 12&lt;br /&gt;
* n = 5&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente [[User:Acsor|Acsor]] in data 23/08/2020. Ritengo sia: corretto&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&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;
==== Punto b) ====&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;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
# Frammentazione interna: allocazioni di pagine la cui dimensione è strettamente maggiore di quella effettivamente richiesta.  Frammentazione esterna: nessuno. Infatti ogni spazio (pagina) allocato e liberato è prima o poi riallocato.&lt;br /&gt;
# Se non viene utilizzato un sistema di caching, una lettura diretta a più blocchi di un file di grandi dimensioni richiede: la lettura della FAT, solitamente posta all'inizio di un [[Glossario#Volume|volume]] (e dunque, su dischi rotazionali, in una traccia differente da quella attuale o da quella del blocco da leggere); la lettura del blocco stesso, e dunque lo spostamento della testina nella traccia e nel settore di interesse&lt;br /&gt;
# Uno scheduling a priorità statica può essere utile ad un processo interattivo, dove è necessario mantenersi all'interno di date soglie temporali o semplicemente svolgere un dato compito con meno ritardo possibile; esempi concreti: un processo che faccia streaming video; un processo appartenente ad un server il cui obiettivo primario è soddisfare le richieste dei propri client il prima possibile, ma dove può anche essere svolta qualche attività dai processi locali (es. programmi applicativi). In uno scheduling a priorità statica, se la presenza di processi ad alte priorità è costante, possono verificarsi indesiderati fenomeni di ''starvation'' nei confronti di processi meno prioritari.&lt;br /&gt;
# ''Domanda puramente nozionistica, la cui risposta può essere ricavata consultando note, lucidi o libri di testo.''&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&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;
    if (buffer.lenght() &amp;gt;= MAX) {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX) {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&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;
    generic_type val;&lt;br /&gt;
&lt;br /&gt;
    if (buffer.lenght() == 0) {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&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;
&lt;br /&gt;
    val = buffer.length() == 0 ? NULL: buffer.dequeue();&lt;br /&gt;
    ok2write.signal();&lt;br /&gt;
&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 ===&lt;br /&gt;
&lt;br /&gt;
* Controllato e corretto dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&lt;br /&gt;
===== Algoritmo MIN =====&lt;br /&gt;
&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;
===== Algoritmo 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;
==== Punto b) ====&lt;br /&gt;
&lt;br /&gt;
Poiché non è specificato quale dei due algoritmi precedenti applicare, sono state considerate soluzioni per ognuno di essi&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo MIN (da controllare) =====&lt;br /&gt;
(È possibile ottenere una stringa più breve?)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
4 3 2 1 5 3 2 1 4 5 3 2 1 3 2 4 5 1 2 4 3 1 5 4 2 1 3 4   &lt;br /&gt;
-------------------------------------------------------&lt;br /&gt;
4|4|4|4|5|  5  |5|  5  |1|  1  |1|  1  |1|  1  |   1   &lt;br /&gt;
 |3|3|3|3|  3  |3|  3  |3|  3  |5|  5  |5|  5  |   2   &lt;br /&gt;
 | |2|2|2|  2  |2|  2  |2|  2  |2|  2  |3|  3  |   3   &lt;br /&gt;
 | | |1|1|  1  |4|  4  |4|  4  |4|  4  |4|  4  |   4   &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo LRU =====&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 1 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 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 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;br /&gt;
&lt;br /&gt;
== Esame Pratico 22/01/2016 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2016.01.22.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dirent.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef struct nameNumber {&lt;br /&gt;
        char *name;&lt;br /&gt;
        int value;&lt;br /&gt;
    } nameNumber;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int prefixToInt (char *string) {&lt;br /&gt;
&lt;br /&gt;
    int i = 0;&lt;br /&gt;
    int num = 0;&lt;br /&gt;
    while (string[i] &amp;gt;= '0' &amp;amp;&amp;amp; string[i] &amp;lt; '9' &amp;amp;&amp;amp; i &amp;lt; strlen(string)) {&lt;br /&gt;
        num = (num*10) + (string[i]-'0');&lt;br /&gt;
        i++;&lt;br /&gt;
    }&lt;br /&gt;
    return num;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void fileSort(struct nameNumber **files) {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int comp (const void * el1, const void * el2) {&lt;br /&gt;
    struct nameNumber *f = *((nameNumber**)el1);&lt;br /&gt;
    struct nameNumber *s = *((nameNumber**)el2);&lt;br /&gt;
    if (f-&amp;gt;value &amp;gt; s-&amp;gt;value) return 1;&lt;br /&gt;
    if (f-&amp;gt;value &amp;lt; s-&amp;gt;value) return -1;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int arg, char* argv[]) {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    struct nameNumber **files;&lt;br /&gt;
&lt;br /&gt;
    DIR *dir;&lt;br /&gt;
    struct dirent *ent;&lt;br /&gt;
&lt;br /&gt;
    int count = 0;&lt;br /&gt;
&lt;br /&gt;
    if((dir = opendir(argv[1])) != NULL) &lt;br /&gt;
    {&lt;br /&gt;
        while( (ent = readdir(dir)) != NULL ) &lt;br /&gt;
        {   &lt;br /&gt;
            if (ent-&amp;gt;d_name[0] &amp;lt; '9' &amp;amp;&amp;amp; ent-&amp;gt;d_name[0] &amp;gt;= '0') &lt;br /&gt;
            {&lt;br /&gt;
                files = (struct nameNumber**)realloc(files , (count+1) * sizeof(struct nameNumber*));&lt;br /&gt;
                files[count] = (struct nameNumber*)malloc(sizeof(struct nameNumber));&lt;br /&gt;
                files[count]-&amp;gt;name = (char*)malloc(sizeof(char)*strlen(ent-&amp;gt;d_name) + 1);&lt;br /&gt;
                strcpy(files[count]-&amp;gt;name, ent-&amp;gt;d_name);&lt;br /&gt;
                files[count]-&amp;gt;value = prefixToInt(files[count]-&amp;gt;name);&lt;br /&gt;
                printf(&amp;quot;name : %s  ,  value : %d\n&amp;quot;, files[count]-&amp;gt;name , files[count]-&amp;gt;value);&lt;br /&gt;
                count++;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    qsort(files, count, sizeof(nameNumber*), comp);&lt;br /&gt;
&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i=0; i &amp;lt; count; i++) {&lt;br /&gt;
        printf(&amp;quot;%s\n&amp;quot;,files[i]-&amp;gt;name);&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;
&lt;br /&gt;
== Esame di Concorrenza del 13/01/2005 ==&lt;br /&gt;
Il testo degli esercizi è disponibile alla pagina http://www.cs.unibo.it/~renzo/so/compiti/2005-01-13.con.pdf.&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
Il codice di questo esercizio può essere eseguito scaricando il sorgente Python e l'archivio relativo agli [[Tool_per_semafori_e_monitor|strumenti di concorrenza per il linguaggio Python]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
import threading&lt;br /&gt;
import random&lt;br /&gt;
import time&lt;br /&gt;
from pysm.semaphore import semaphore&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class mod_counter:&lt;br /&gt;
    def __init__(self, mod, start=0):&lt;br /&gt;
        self._mod = mod&lt;br /&gt;
        self._val = start&lt;br /&gt;
&lt;br /&gt;
    def inc(self):&lt;br /&gt;
        self._val = (self._val + 1) % self._mod&lt;br /&gt;
&lt;br /&gt;
    def get(self):&lt;br /&gt;
        return self._val&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class process(threading.Thread):&lt;br /&gt;
    def __init__(self, to_print, c: mod_counter, a, t, r):&lt;br /&gt;
        threading.Thread.__init__(self, name=&amp;quot;proc&amp;quot; + to_print)&lt;br /&gt;
&lt;br /&gt;
        if to_print not in &amp;quot;tar&amp;quot;:&lt;br /&gt;
            raise ValueError(&amp;quot;Unexpected printable character:&amp;quot;, to_print)&lt;br /&gt;
&lt;br /&gt;
        self._counter = c&lt;br /&gt;
        self._x = to_print&lt;br /&gt;
        self._semaphores = {'t': t, 'a': a, 'r': r}&lt;br /&gt;
        self._enter = True&lt;br /&gt;
&lt;br /&gt;
        if self._x == 't':&lt;br /&gt;
            self._semaphores[self._x].V()&lt;br /&gt;
&lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            self.sync()&lt;br /&gt;
            print(&amp;quot;[%s] %c&amp;quot; % (self.name, self._x))&lt;br /&gt;
&lt;br /&gt;
            # Print a trailing newline&lt;br /&gt;
            if (self._counter.get() == 7):&lt;br /&gt;
                print()&lt;br /&gt;
&lt;br /&gt;
            time.sleep(random.random() * 0.5)&lt;br /&gt;
&lt;br /&gt;
    def sync(self):&lt;br /&gt;
        if (self._enter):&lt;br /&gt;
            self._semaphores[self._x].P()&lt;br /&gt;
            self._enter = False&lt;br /&gt;
        else:&lt;br /&gt;
            self._counter.inc()&lt;br /&gt;
            curr = &amp;quot;taratata&amp;quot;[self._counter.get()]&lt;br /&gt;
&lt;br /&gt;
            self._semaphores[curr].V()&lt;br /&gt;
&lt;br /&gt;
            self._enter = True&lt;br /&gt;
            self.sync()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    counter = mod_counter(8)&lt;br /&gt;
    semaphores = (semaphore(0), semaphore(0), semaphore(0))&lt;br /&gt;
    procs = [process(c, counter, *semaphores) for c in &amp;quot;tar&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.daemon = True&lt;br /&gt;
        p.start()&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
	<entry>
		<id>https://so.v2.cs.unibo.it/wiki/index.php?title=Prove_svolte_e_soluzioni_proposte&amp;diff=2568</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=2568"/>
		<updated>2020-08-27T18:36:34Z</updated>

		<summary type="html">&lt;p&gt;Acsor: Svolto es c.2 dell'esame del 12/02/2018&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Questa pagina raccoglie prove d'esame svolte (che possono essere utili alla preparazione) e soluzioni proposte a tali prove da sottoporre a peer-review. Chiunque prenda visione di un esercizio è pregato (per il bene collettivo) a lasciare una [https://www.mediawiki.org/wiki/Help:Signatures propria firma] con nome utente e data di visualizzazione indicando se lo svolgimento è ritenuto corretto; in caso di svolgimento scorretto è invece invitato ad apportare una correzione, lasciando come nel caso precedente il proprio nome utente e data di correzione.&lt;br /&gt;
&lt;br /&gt;
Al fine di verificare la correttezza degli esercizi di concorrenza, segnaliamo la presenza di [[Tool_per_semafori_e_monitor|strumenti di programmazione concorrente]] per i linguaggi C e Python.&lt;br /&gt;
&lt;br /&gt;
== Esame 13/09/2019 ==&lt;br /&gt;
Testo: [https://www.cs.unibo.it/~renzo/so/compiti/2019.09.13.tot.pdf 2019.09.13.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
Controllato dal professor Davoli durante la lezione del 19/05/2020.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Andrea R.&lt;br /&gt;
&lt;br /&gt;
monitor mbuf:&lt;br /&gt;
    waiting = 0&lt;br /&gt;
    queue&amp;lt;pair&amp;lt;T, int&amp;gt;&amp;gt; q    # (dato, molteplicità)&lt;br /&gt;
    condition ok2add         # q.length() &amp;lt; MAXELEM&lt;br /&gt;
    condition ok2get         # q.length() &amp;gt; 0&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    entry void add(T data, int n):&lt;br /&gt;
        if q.length() &amp;gt;= MAXELEM:&lt;br /&gt;
            ok2add.wait()&lt;br /&gt;
&lt;br /&gt;
        q.enqueue({data, n})&lt;br /&gt;
&lt;br /&gt;
        if waiting &amp;gt;= q.front().second:&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    entry T get():&lt;br /&gt;
        waiting++                                        # vuole ricevere&lt;br /&gt;
        if q.empty() or waiting &amp;lt; q.front().second:      # cortocircuitato&lt;br /&gt;
            ok2get.wait()&lt;br /&gt;
&lt;br /&gt;
        x = q.front().first&lt;br /&gt;
        q.front().second--&lt;br /&gt;
        waiting--                    # riceve&lt;br /&gt;
&lt;br /&gt;
        if q.front().second &amp;gt; 0:     # cascata&lt;br /&gt;
            ok2get.signal()&lt;br /&gt;
        else:                        # ultimo che riceve&lt;br /&gt;
            q.dequeue()&lt;br /&gt;
            ok2add.signal()&lt;br /&gt;
        return x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 15/07/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.07.15.tot.pdf 2019.07.15.tot.pdf]&lt;br /&gt;
=== Esercizio c.1 ===&lt;br /&gt;
&lt;br /&gt;
# Verifica del 18/05/2020 dell'utente [[User:Acsor|Acsor]]. Ritengo sia: corretto&lt;br /&gt;
# Verifica del ... dell'utente ... . Ritengo sia: ...&lt;br /&gt;
# ...&lt;br /&gt;
&lt;br /&gt;
Una semplice realizzazione in Python dello pseudocodice seguente è disponibile [https://github.com/pollomarzo/rdso1920/tree/master/2019exams/samepc qui].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca, Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors: utente Acsor&lt;br /&gt;
&lt;br /&gt;
monitor pair_buffer:&lt;br /&gt;
    int nw, nr;&lt;br /&gt;
    queue buffer;&lt;br /&gt;
    condition same_number;&lt;br /&gt;
&lt;br /&gt;
    pair_buffer():&lt;br /&gt;
        nw = nr = 0&lt;br /&gt;
        buffer = queue()&lt;br /&gt;
        same_number = condition()&lt;br /&gt;
    &lt;br /&gt;
    @entry&lt;br /&gt;
    put(T x):&lt;br /&gt;
        nw++;&lt;br /&gt;
        buffer.enqueue(x);&lt;br /&gt;
        &lt;br /&gt;
        if nw != nr:&lt;br /&gt;
            same_number.wait();&lt;br /&gt;
            &lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nw--;&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    T get(void):&lt;br /&gt;
        nr++;&lt;br /&gt;
&lt;br /&gt;
        if nw != nr: &lt;br /&gt;
            same_number.wait();&lt;br /&gt;
        else:&lt;br /&gt;
            same_number.signal();&lt;br /&gt;
        &lt;br /&gt;
        T val = buffer.dequeue();&lt;br /&gt;
        same_number.signal();&lt;br /&gt;
        nr--;&lt;br /&gt;
&lt;br /&gt;
        return val;&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 18/06/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.06.18.tot.pdf 2019.06.18.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 pg{&lt;br /&gt;
&lt;br /&gt;
  int waitingReader = 0;&lt;br /&gt;
  int waitingWriter = 0;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write;&lt;br /&gt;
  condition ok2read;&lt;br /&gt;
&lt;br /&gt;
  T datobuf;&lt;br /&gt;
&lt;br /&gt;
  entry put (T dato) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0)&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
      while (waitingReader &amp;gt; 0)&lt;br /&gt;
        ok2read.signal();&lt;br /&gt;
    else if (waitingWriter &amp;gt;= 0)&lt;br /&gt;
      waitingWriter++;&lt;br /&gt;
      ok2write.wait();&lt;br /&gt;
      waitingWriter--;&lt;br /&gt;
      datobuf = dato;&lt;br /&gt;
&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry T get (void) {&lt;br /&gt;
&lt;br /&gt;
    if (waitingReader &amp;gt; 0 || waitingWriter == 0)&lt;br /&gt;
      waitingReader++;&lt;br /&gt;
      ok2read.wait();&lt;br /&gt;
      waitingReader--;&lt;br /&gt;
    else if (waitingWriter &amp;gt; 0) &lt;br /&gt;
      ok2write.signal();&lt;br /&gt;
      return datobuf;&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 c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor taon {&lt;br /&gt;
condition ok2w, ok2r;&lt;br /&gt;
int nw, nr = 0;&lt;br /&gt;
T buf;&lt;br /&gt;
&lt;br /&gt;
entry  void put (T dato){&lt;br /&gt;
	nw++;&lt;br /&gt;
	if( nw != 1 || nr == 0)&lt;br /&gt;
             ok2w.wait();&lt;br /&gt;
	buf = dato;&lt;br /&gt;
	for (i=0, i++, i &amp;lt; nr)&lt;br /&gt;
	     ok2r.signal();&lt;br /&gt;
	nw--;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
entry T get(){&lt;br /&gt;
	nr++;&lt;br /&gt;
	if(nw==0)&lt;br /&gt;
	    ok2r.wait();&lt;br /&gt;
	ok2w.signal();&lt;br /&gt;
	T dato = buf;&lt;br /&gt;
	nr --;&lt;br /&gt;
	return dato;&lt;br /&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;
/* 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;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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.&lt;br /&gt;
# 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 18/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente Lusvelt in data 26/08/2020 (sbagliato, dal testo si evince che se manca anche solo un componente bisogna mettersi in attesa finchè non arrivi, per poi prendere anche gli altri).&lt;br /&gt;
:: E non è quel che già accade nel ramo else di get()? C'è una wait() ed essa è invocata proprio quando components[i] &amp;gt; self._v[i]. (La chat in Wiki è scomoda, sentiamoci su Telegram.) -- [[User:Acsor|Acsor]] ([[User talk:Acsor|talk]]) 17:32, 26 August 2020 (CEST)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Il sorgente seguente può essere eseguito scaricando in una stessa directory il package [[Tool per semafori e monitor|pysm]] del prof. Davoli.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
import threading&lt;br /&gt;
&lt;br /&gt;
from array import array&lt;br /&gt;
from pysm.monitor import condition, entry, monitor&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class storage(monitor):&lt;br /&gt;
    ELEMS = 16&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Implementazione che permette l'avanzamento degli operai in presenza di&lt;br /&gt;
    altri operai in attesa.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        monitor.__init__(self)&lt;br /&gt;
        self._v = array('L', self.ELEMS * [0])&lt;br /&gt;
        self._c = tuple(condition(self) for i in self._v)&lt;br /&gt;
        # self._requests[i] = [l1, l2, ..., ln] se per l'attrezzo i ci sono in&lt;br /&gt;
        # attesa n processi che richiedono ciascuno l1, l2, ..., ln unita'&lt;br /&gt;
        self._requests = {i: list() for i in range(self.ELEMS)}&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def add(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i, c in enumerate(components):&lt;br /&gt;
            self._v[i] += c&lt;br /&gt;
&lt;br /&gt;
            # Finche' per il componente i ci sono richieste in sospeso che&lt;br /&gt;
            # possono essere soddisfatte, svegliamo il processo in attesa, che&lt;br /&gt;
            # proseguira' col richiedere i componenti successivi&lt;br /&gt;
            while self._requests[i] and self._requests[i][0] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._c[i].signal()&lt;br /&gt;
&lt;br /&gt;
    @entry&lt;br /&gt;
    def get(self, components):&lt;br /&gt;
        if len(components) != self.ELEMS:&lt;br /&gt;
            raise ValueError(&amp;quot;components must contain exactly ELEMS elements&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        for i in range(len(components)):&lt;br /&gt;
            if components[i] &amp;lt;= self._v[i]:&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
            else:&lt;br /&gt;
                components[i] -= self._v[i]&lt;br /&gt;
                self._v[i] = 0&lt;br /&gt;
&lt;br /&gt;
                self._requests[i].append(components[i])&lt;br /&gt;
                self._c[i].wait()&lt;br /&gt;
&lt;br /&gt;
                self._v[i] -= components[i]&lt;br /&gt;
                self._requests[i].pop(0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def request(m, q):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula la richiesta di un operaio.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Requesting %s&amp;quot; % (name, q))&lt;br /&gt;
    m.get(q)&lt;br /&gt;
    print(&amp;quot;[%s] Done requesting&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def supply(m, s):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Funzione processo che simula il rifornimento di un magazziniere.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    name = threading.current_thread().name&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;[%s] Supplying %s&amp;quot; % (name, s))&lt;br /&gt;
    m.add(s)&lt;br /&gt;
    print(&amp;quot;[%s] Done supplying&amp;quot; % (name))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    m = storage()&lt;br /&gt;
    requests = [&lt;br /&gt;
        threading.Thread(name='req1', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req2', target=request, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req3', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req4', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='req5', target=request, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
    supplies = [&lt;br /&gt;
        threading.Thread(name='supply1', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply2', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply3', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply4', target=supply, args=(m, [4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
        threading.Thread(name='supply5', target=supply, args=(m, [0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])),&lt;br /&gt;
    ]&lt;br /&gt;
&lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.daemon = True&lt;br /&gt;
        t.start()&lt;br /&gt;
    &lt;br /&gt;
    for t in requests + supplies:&lt;br /&gt;
        t.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&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;
unsigned procs_in = 0;&lt;br /&gt;
semaphore mutex = new binary_semaphore(1);&lt;br /&gt;
queue&amp;lt;semaphore&amp;gt; semaphores = new queue&amp;lt;&amp;gt;();&lt;br /&gt;
&lt;br /&gt;
sau_enter () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in++;&lt;br /&gt;
	mutex.V();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sau_exit () {&lt;br /&gt;
	mutex.P();&lt;br /&gt;
	procs_in--;&lt;br /&gt;
&lt;br /&gt;
	if (procs_in &amp;gt; 0) {&lt;br /&gt;
		semaphore s = new semaphore(0);&lt;br /&gt;
&lt;br /&gt;
		semaphores.enqueue(s);&lt;br /&gt;
		mutex.V();&lt;br /&gt;
		s.P();&lt;br /&gt;
	} else {&lt;br /&gt;
		while (!sempahores.empty())&lt;br /&gt;
			semaphores.dequeue().V();&lt;br /&gt;
&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;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
==== Domanda a) ====&lt;br /&gt;
Poiché lo scheduler è non-preemptive, una volta assegnata la CPU ad un dato processo, questi non viene cambiato finché non ha terminato. Visto il vincolo nel testo della consegna, una volta concluso il processo corrente si hanno solo due scelte: selezionare il più recente processo A o il più recente processo B.&lt;br /&gt;
&lt;br /&gt;
Nuovi processi A partono ogni 6ms, nuovi processi B ogni 8ms; gli intervalli di tempo in cui partono sia processi A sia processi B sono multipli di mcm(6, 8) ms = 24ms: cioè ai tempi 0ms, 24ms, 48ms, 72ms, ..., parte sia un processo A sia un processo B.&lt;br /&gt;
&lt;br /&gt;
In ognuno di questi intervalli di 24ms, si susseguono sia processi A sia processi B. I processi A sono 24ms / 6ms = 4, i processi B 24ms / 8ms = 3; i primi richiedono 4 * 3ms = 12ms, i secondi 3 * 4ms = 12ms. È possibile dimostrare induttivamente che ad ogni nuovo intervallo di 24ms, i processi di quello precedente sono stati tutti svolti e che quelli correnti saranno terminati entro 24ms (infatti ad ogni 24ms, è un po' come se le condizioni iniziali venissero ristabilite). Pertanto è possibile eseguire entrambi i processi senza portare a starvation.&lt;br /&gt;
&lt;br /&gt;
==== Domanda b) ====&lt;br /&gt;
Ragionamento analogo al punto precedente, con alcune differenze date dalle permutazioni in cui certi processi vengono schedulati.&lt;br /&gt;
&lt;br /&gt;
==== Domanda c) ====&lt;br /&gt;
Per definizione, uno scheudler round-robin garantisce possibilità di esecuzione a tutti i processi, pertanto è possibile. La figura mostra un intervallamento di scheduling secondo criterio RR che evidenzia come sia possibile completare tutti i processi entro i 24ms.&lt;br /&gt;
&lt;br /&gt;
[[File:Epson 25082020151034.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
# Basso, perché vengono generate molte page trap. Così facendo i processi direttamente interessati devono attendere il caricamento delle pagine di memoria ed essere posti in attesa, riducendo l'utilizzazione della CPU.&lt;br /&gt;
# Sì, ad esempio il MBR (Master Boot Record) e l'area di swap. Il MBR contiene meta-informazioni sul disco stesso e non è adatto a contenere informazioni concrete, mentre l'area di swap può essere considerata un'estensione della memoria centrale del calcolatore.&lt;br /&gt;
# Flessibile, perché se intendo riconfigurare alcuni parametri del sistema non occorre ricompilare il kernel, ma solamente riscrivere/riconfigurare e rilanciare il programma che si fa carico del servizio in questione; affidabile, in quanto i servizi di sistema sono realizzati tramite processi a livello utente, e un loro crash non si ripercuote sull'intero sistema; meno efficiente (di un kernel monolitico) in quanto i vari servizi comunicano con il kernel non tramite chiamate di sistema, ma un vero e proprio servizio di message passing tra processi, che aggiunge overhead.&lt;br /&gt;
# Come voci di una directory che puntano allo stesso inode (laddove il file system sia basato su inode) o più in generale allo stesso FCB (File Control Block). Per determinare se un dato FCB non è più linkato da nessuna voce (entry) si utilizza un contatore che rappresenta il numero corrente di riferimenti; quando questo diventa 0, il FCB può essere eliminato dal file system.&lt;br /&gt;
&lt;br /&gt;
== Esame 14/02/2019 ==&lt;br /&gt;
[https://www.cs.unibo.it/~renzo/so/compiti/2019.02.14.tot.pdf testo esame]&lt;br /&gt;
=== Esercizio c.1 (possibile soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original authors: Mattia Guazzaloca &amp;amp; Paolo Marzolo&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
class monobinarysem(monitor):&lt;br /&gt;
    def __init__(self, val):&lt;br /&gt;
        self.iszero = condition(self)&lt;br /&gt;
        self.val = val&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoP(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.iszero.wait()&lt;br /&gt;
        &lt;br /&gt;
        self.val -= 1&lt;br /&gt;
        &lt;br /&gt;
    @entry&lt;br /&gt;
    def monoV(self):&lt;br /&gt;
        if self.val == 0:&lt;br /&gt;
            self.val += 1&lt;br /&gt;
            self.iszero.signal()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
=== Esercizio c.2 (soluzione corretta) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# Original author: Renzo Davoli (durante la lezione)&lt;br /&gt;
#&lt;br /&gt;
# Contributors:&lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
def pssend(message, destination):&lt;br /&gt;
    asend((self(),message),destination)&lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == ACK):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
def psreceive(sender):&lt;br /&gt;
    dummy = Message(null)&lt;br /&gt;
    asend(self(),dummy) //self is my id&lt;br /&gt;
    &lt;br /&gt;
    while(1):&lt;br /&gt;
        snd, message = arecv(ANY)&lt;br /&gt;
        if(message == dummy):&lt;br /&gt;
            break&lt;br /&gt;
        datastruct.add(snd, message)&lt;br /&gt;
        &lt;br /&gt;
    if (datastruct.match(sender)):&lt;br /&gt;
        src, msg = datastruct.get(sender)&lt;br /&gt;
        asend((self(),ACK), src)&lt;br /&gt;
        return msg&lt;br /&gt;
    else:&lt;br /&gt;
        return None&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Esame 28/05/2019 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2019.05.18.tot.pdf 2019.05.18.tot.pdf]&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;
&lt;br /&gt;
monitor storage:&lt;br /&gt;
   &lt;br /&gt;
    [16] int vector&lt;br /&gt;
    [16] condition ok2get&lt;br /&gt;
    [16] bool available = { 1, ..., 1 }&lt;br /&gt;
   &lt;br /&gt;
    entry get([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            while ((components[i] &amp;gt; vector[i]) || !available[i]):&lt;br /&gt;
                if (available[i]):&lt;br /&gt;
                    available[i] = false&lt;br /&gt;
                ok2get[i].wait()&lt;br /&gt;
            vector[i] -= components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
  &lt;br /&gt;
    entry add([16] int components):&lt;br /&gt;
        for (i from 0 to 15):&lt;br /&gt;
            vector[i] += components[i]&lt;br /&gt;
            available[i] = true&lt;br /&gt;
            ok2get[i].signal()&lt;br /&gt;
&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;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor storage{&lt;br /&gt;
	int stored[16]&lt;br /&gt;
	int components[16]&lt;br /&gt;
	condition ok2make[16]&lt;br /&gt;
	boolean required[16] //false&lt;br /&gt;
	&lt;br /&gt;
	void add(components){&lt;br /&gt;
		stored += components;&lt;br /&gt;
		for(i=0; i&amp;lt; 16; i ++){&lt;br /&gt;
			if(required[i] == true)&lt;br /&gt;
				ok2make(i).signal();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	void get(components){&lt;br /&gt;
		for(i = 0; i&amp;lt; 16; i++){&lt;br /&gt;
			if (stored[i] &amp;gt;= components[i])&lt;br /&gt;
				stored[i] -= components[i]&lt;br /&gt;
			else&lt;br /&gt;
				required[i] = true&lt;br /&gt;
				ok2make(i).wait();&lt;br /&gt;
				required[i] = false&lt;br /&gt;
				i—;&lt;br /&gt;
&lt;br /&gt;
		}&lt;br /&gt;
	}&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 19/09/2018 ==&lt;br /&gt;
[http://www.cs.unibo.it/~renzo/so/compiti/2018.09.19.tot.pdf]&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Nello pseudocodice seguente, il termine this fa riferimento al processo corrente, mentre ANY ad uno qualunque.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
stack&amp;lt;message&amp;gt; messages;&lt;br /&gt;
&lt;br /&gt;
void lifo_send(string m, process dest) {&lt;br /&gt;
	do {&lt;br /&gt;
		asend(m, dest);&lt;br /&gt;
	} while (areceive(dest).text != &amp;quot;ACK&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
message lifo_receive(process source) {&lt;br /&gt;
	if (source != ANY) {&lt;br /&gt;
		message m = areceive(source);&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;ACK&amp;quot;, source);&lt;br /&gt;
&lt;br /&gt;
		return m;&lt;br /&gt;
	} else {&lt;br /&gt;
		message m;&lt;br /&gt;
&lt;br /&gt;
		asend(&amp;quot;END&amp;quot;, this);&lt;br /&gt;
		m = areceive(ANY);&lt;br /&gt;
&lt;br /&gt;
		while (m.text != &amp;quot;END&amp;quot; || m.sender != this) {&lt;br /&gt;
			messages.push(m);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                /* Bisogna tenere conto dei casi in cui lifo_receive() viene invocata quando nessun&lt;br /&gt;
                 * messaggio è stato ancora spedito da altri processi. In tal caso si attende il&lt;br /&gt;
                 * il primo e lo si restituisce.&lt;br /&gt;
                 */&lt;br /&gt;
		if (messages.empty()) {&lt;br /&gt;
			m = areceive(ANY);&lt;br /&gt;
			asend(&amp;quot;ACK&amp;quot;, m.sender);&lt;br /&gt;
&lt;br /&gt;
			return m;&lt;br /&gt;
		} else {&lt;br /&gt;
			return messages.pop();&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&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;
* Visto e corretto dall'utente [[User:Acsor|Acsor]] in data 23/08/2020&lt;br /&gt;
* Visto e corretto dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
class LIFOBuffer {&lt;br /&gt;
	stack&amp;lt;T&amp;gt; s;&lt;br /&gt;
	semaphore mutex(1); // mutua esclusione&lt;br /&gt;
	semaphore ok2consume(0);&lt;br /&gt;
&lt;br /&gt;
	void push (T value) {&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		s.push(value);&lt;br /&gt;
                // (1)&lt;br /&gt;
		mutex.V()&lt;br /&gt;
&lt;br /&gt;
		ok2consume.V()  // Curiosità: che succede se spostiamo quest'istruzione in (1)?&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	T pop () {&lt;br /&gt;
		T value;&lt;br /&gt;
&lt;br /&gt;
		ok2consume.P();&lt;br /&gt;
		mutex.P();&lt;br /&gt;
		value = s.pop();&lt;br /&gt;
		mutex.V();&lt;br /&gt;
&lt;br /&gt;
		return value;&lt;br /&gt;
	}&lt;br /&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;
# In sistemi dove dispositivi di archiviazione o supporti hardware per la memoria virtuale (e dunque per la paginazione, spesso utilizzata per realizzare il supporto di memoria virtuale) non sono presenti (es. sistemi embedded). ''(In sistemi real-time la memoria virtuale è praticabile? Annotare.)''&lt;br /&gt;
# 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.&lt;br /&gt;
# Per fornire parallelismo e ridondanza. Non è necessario fare backup dei dati sul disco, nel senso di mantenere una copia identica di dati già memorizzati altrove, in quanto diversi sistemi di codici permettono il rilevamento e/o la correzione di errori.&lt;br /&gt;
# Se in un grafo di Holt multirisorsa esiste un ciclo tra più processi e risorse, ciò non significa che allo stesso tempo non siano coinvolti processi con archi esclusivamente entranti. Ogni processo appartenente a questa categoria non è in attesa di risorse, e può dunque procedere con i suoi calcoli; quando avrà terminato rilascerà le risorse precedentemente allocategli, eventualmente sbloccando uno dei processi coinvolti nel ciclo.&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;
        } else if (okmax.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmax.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
        } else if (okmin.length() &amp;gt; 0) {&lt;br /&gt;
            s = okmin.dequeue()&lt;br /&gt;
            s.V();&lt;br /&gt;
            mutex.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;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
proc[x]: x='a',...,'z'&lt;br /&gt;
 while True:&lt;br /&gt;
  //c sarà il carattere stampato dal processo precedente&lt;br /&gt;
  (c, string) = arecv(*)&lt;br /&gt;
  if(string == wait){&lt;br /&gt;
    //mi metto in attesa di ricevere l'ACK da proc[x]&lt;br /&gt;
    m=arecv(x);&lt;br /&gt;
  }&lt;br /&gt;
  if (c == NONE){&lt;br /&gt;
    //significa che sei il primo a ricevere quella stringa&lt;br /&gt;
    print(x);&lt;br /&gt;
    if (len(string) &amp;gt; 1){&lt;br /&gt;
      //mando la wait a tutti, il primo che riceve qualcosa da stampare manda una wait a tutti&lt;br /&gt;
      asend(wait,*);&lt;br /&gt;
      int l = len(string);&lt;br /&gt;
      int i = 1;&lt;br /&gt;
      while(l != 0){&lt;br /&gt;
        asend(proc[string[i]], (x, string[i...]));&lt;br /&gt;
        //si mette in attesa di ricevere l'ACK dal processo dell'ultima lettera della parola&lt;br /&gt;
        m=areceive(proc[string[i]]);&lt;br /&gt;
        //rimando la wait al processo per ribloccarlo&lt;br /&gt;
        asend(wait, proc[string[i]])&lt;br /&gt;
        l--;&lt;br /&gt;
        i++;&lt;br /&gt;
      }&lt;br /&gt;
      //dopo aver finito la stampa della stringa sblocco tutti i processi&lt;br /&gt;
      asend(ACK, *);&lt;br /&gt;
    }&lt;br /&gt;
  }else{&lt;br /&gt;
    print(x);&lt;br /&gt;
    asend(ACK, x);&lt;br /&gt;
    //ricomincia il ciclo while, si rimette in attesa e il 'gestore gli rimanda la wait'&lt;br /&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;
&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;
&lt;br /&gt;
monitor bridge:&lt;br /&gt;
&lt;br /&gt;
    int ncar&lt;br /&gt;
    bool boat_on_0&lt;br /&gt;
    bool boat_on_1       // per semplicità, quando nel codice si trova boat_on_(direction) oppure isBoat(direction)(),&lt;br /&gt;
                         // si valuta il valore booleano di direction e lo si applica sotto forma di stringa al simbolo&lt;br /&gt;
                         // ad esso adiacente&lt;br /&gt;
    bool is_raised&lt;br /&gt;
    queue waiting_mean   // i valori possibili sono: boat0, boat1 oppure car&lt;br /&gt;
    condition ok2go&lt;br /&gt;
  &lt;br /&gt;
    entry car_enter(direction): &lt;br /&gt;
        if is_raised || ncar == MAXCAR:&lt;br /&gt;
            waiting_mean.enqueue(car)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        is_raised = false&lt;br /&gt;
        ++ncar&lt;br /&gt;
  &lt;br /&gt;
    entry car_exit(direction):&lt;br /&gt;
        --ncar&lt;br /&gt;
        if (waiting_mean.top().isBoat() &amp;amp;&amp;amp; ncar == 0) || waiting_mean.top().isCar():    // isBoat ritorna true se l'oggetto su cui&lt;br /&gt;
            waiting_mean.dequeue()                                                      // è invocata è boat0 oppure boat1&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
  &lt;br /&gt;
    entry boat_enter(direction):&lt;br /&gt;
        if !is_raised || boat_on_(direction):&lt;br /&gt;
            waiting_mean.enqueue(boat)&lt;br /&gt;
            ok2go.wait()&lt;br /&gt;
        if waiting_mean.top().isBoat(!direction)():&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
        is_raised = true&lt;br /&gt;
        boat_on_(direction) = true&lt;br /&gt;
  &lt;br /&gt;
    entry boat_exit(direction):&lt;br /&gt;
        boat_on_(direction) = false&lt;br /&gt;
        if !boat_on_(!direction):&lt;br /&gt;
            waiting_mean.dequeue()&lt;br /&gt;
            ok2go.signal()&lt;br /&gt;
&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;
=== 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;
entry 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;
entry 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;
entry 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;
entry 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 (da controllare) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
monitor bridge {&lt;br /&gt;
&lt;br /&gt;
  UP=0;&lt;br /&gt;
  DOWN=1;&lt;br /&gt;
  bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
  bool carAreExiting = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2drive;&lt;br /&gt;
  condition ok2barca[2];&lt;br /&gt;
&lt;br /&gt;
  waitingCar = 0;&lt;br /&gt;
  carOnBridge = 0;&lt;br /&gt;
&lt;br /&gt;
  boatWaiting[2] = {0,0};&lt;br /&gt;
  boatIsPassing[2] = {false,false}&lt;br /&gt;
&lt;br /&gt;
  entry car_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == DOWN)&lt;br /&gt;
      if(carOnBridge == MAXCAR)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
      else if (carAreExiting)&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
    else &lt;br /&gt;
      if (boatIsPassing[0] || boatIsPassing[1])&lt;br /&gt;
        waitingCar++;&lt;br /&gt;
        ok2drive.wait();&lt;br /&gt;
        waitingCar--;&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
&lt;br /&gt;
    carOnBridge++;&lt;br /&gt;
    carAreExiting = false;&lt;br /&gt;
    if(carOnBridge &amp;lt; MAXCAR &amp;amp;&amp;amp; !carAreExiting) &lt;br /&gt;
      ok2drive.signal();&lt;br /&gt;
      &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry car_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    carOnBridge--;&lt;br /&gt;
    carAreExiting = true;&lt;br /&gt;
&lt;br /&gt;
    if(carOnBridge == 0)&lt;br /&gt;
      carAreExiting = false;&lt;br /&gt;
      if(boatWaiting[0] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[0].signal();&lt;br /&gt;
      else if (boatWaiting[1] &amp;gt; 0)&lt;br /&gt;
        bridgeis = UP;&lt;br /&gt;
        ok2barca[1].signal();&lt;br /&gt;
      else &lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_enter(direction) {&lt;br /&gt;
&lt;br /&gt;
    if (bridgeis == UP)&lt;br /&gt;
    | if (boatIsPassing[direction] == true)&lt;br /&gt;
    | |  boatWaiting[direction]++;&lt;br /&gt;
    | |  ok2barca.wait();&lt;br /&gt;
    | |  boatWaiting[direction]--;&lt;br /&gt;
    else &lt;br /&gt;
    | if (carOnBridge &amp;gt; 0)&lt;br /&gt;
    | | boatWaiting[direction]++;&lt;br /&gt;
    | | ok2barca.wait();&lt;br /&gt;
    | | boatWaiting[direction]--;&lt;br /&gt;
    | | bridgeis = UP;&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = true;&lt;br /&gt;
&lt;br /&gt;
    if(boatIsPassing[1-direction] == false &amp;amp;&amp;amp; boatWaiting[1-direction] &amp;gt; 0)&lt;br /&gt;
      ok2barca[1-direction].signal();&lt;br /&gt;
    &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry boat_exit(direction) {&lt;br /&gt;
&lt;br /&gt;
    boatIsPassing[direction] = false;&lt;br /&gt;
&lt;br /&gt;
    if (boatIsPassing[1-direction] == false)&lt;br /&gt;
      if (waitingCar &amp;gt; 0)&lt;br /&gt;
        bridgeis = DOWN;&lt;br /&gt;
        ok2drive.signal();&lt;br /&gt;
    else&lt;br /&gt;
        if (waitingCar == 0)&lt;br /&gt;
          ok2barca[direction].signal();&lt;br /&gt;
          &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&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;
entry 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;
entry 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;
entry 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;
entry 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;
&lt;br /&gt;
=== Esercizio c.2 (sbagliato) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
list printed_msg;  # questa è una variabile condivisa che ai fini dell'esercizio non si può utilizzare (message passing)&lt;br /&gt;
&lt;br /&gt;
process server[i]:&lt;br /&gt;
  while true:&lt;br /&gt;
    &amp;lt;msg, pid&amp;gt; = arecv(*)&lt;br /&gt;
    if printed_msg.length == 0 or &amp;lt;msg, pid&amp;gt; is not in printed_msg:&lt;br /&gt;
      printed_msg.append(&amp;lt;msg,id&amp;gt;)&lt;br /&gt;
      print(msg)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio c.2 (da controllare) ===&lt;br /&gt;
Nello svolgimento seguente, receiver incapsula l'ambiente privato del processo; _peers rappresenta il vettore di processi &amp;quot;fratelli&amp;quot; ai quali può essere chiesto di stampare un messaggio, mentre _printed contiene l'hash di tutti i messaggi stampati dal processo locale. Si suppone che istanze della classe receiver possano essere passate come parametro ad areceive() ed asend() (non implementate).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
class receiver:&lt;br /&gt;
    def __init__(self, peers):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :param peers: list of processes this process communicates with.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        self._peers = tuple(peers)&lt;br /&gt;
        self._printed = list()&lt;br /&gt;
    &lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            process, message = areceive(ANY)&lt;br /&gt;
&lt;br /&gt;
            if process in self._peers:&lt;br /&gt;
                self._reply_query(process, message)&lt;br /&gt;
            else:&lt;br /&gt;
                self._print(process, message)&lt;br /&gt;
&lt;br /&gt;
    def _print(self, sender, message):&lt;br /&gt;
        h = hash(message.text)&lt;br /&gt;
&lt;br /&gt;
        if h not in self._printed and not self._printed_from_peers(message):&lt;br /&gt;
            self._printed.append(h)&lt;br /&gt;
            print(message.text)&lt;br /&gt;
&lt;br /&gt;
    def _reply_query(self, sender, h):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        Invoked when the current process receive a &amp;quot;query&amp;quot; from a peer process.&lt;br /&gt;
        `h` contains the hash of a message which may or may have not been&lt;br /&gt;
        sent from this process; if it was sent, the reply is `Yes`, otherwise `No`.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        reply = &amp;quot;Yes&amp;quot; if int(h) in self._printed else &amp;quot;No&amp;quot;&lt;br /&gt;
        asend(sender, reply)&lt;br /&gt;
&lt;br /&gt;
    def _printed_from_peers(self, message):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        :return: `True` if this message has already been sent from any of the&lt;br /&gt;
        peer processes, `False` otherwise.&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        h = hash(message)&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            asend(p, str(h))&lt;br /&gt;
&lt;br /&gt;
        for p in self._peers:&lt;br /&gt;
            _, reply = areceive(p)&lt;br /&gt;
&lt;br /&gt;
            if reply.text == &amp;quot;Yes&amp;quot;:&lt;br /&gt;
                return True&lt;br /&gt;
            else if reply.text != &amp;quot;No&amp;quot;:&lt;br /&gt;
                # If the response is neither &amp;quot;Yes&amp;quot; nor &amp;quot;No&amp;quot;, then we have got a query&lt;br /&gt;
                self._reply_query(p, reply)&lt;br /&gt;
&lt;br /&gt;
        return False&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 (da controllare) ===&lt;br /&gt;
Sulla base dei valori in entrata, è possibile costruire le matrici Allocation (q.tà di risorse allocate per processo e per tipo), Need (q.tà di risorse che ogni processo potrebbe ancora chiedere) e il vettore Available (num. di risorse correntemente disponibili).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left&amp;quot;&lt;br /&gt;
! colspan=3 | Allocation&lt;br /&gt;
|-&lt;br /&gt;
   !   !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 4 || 5&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 3 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 2 || 4&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=3 | Need&lt;br /&gt;
|-&lt;br /&gt;
   !    !! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | p1 || 6 || 8&lt;br /&gt;
|-&lt;br /&gt;
   | p2 || 6 || 3&lt;br /&gt;
|-&lt;br /&gt;
   | p3 || 6 || 8&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float: left; margin-left: 1em&amp;quot;&lt;br /&gt;
! colspan=2 | Available&lt;br /&gt;
|-&lt;br /&gt;
   ! A !! B&lt;br /&gt;
|-&lt;br /&gt;
   | x || y&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nel caso delle risorse di tipo A, deve aversi x &amp;gt;= 6 in quanto un processo dovrà essere selezionato come primo nella permutazione dell'algoritmo del banchiere multivaluta, e tutti quelli correnti hanno lo stesso valore Need(i)(1); per ciò che riguarda le risorse di tipo B, possiamo ragionare per esaustione&lt;br /&gt;
&lt;br /&gt;
* Se il primo processo della permutazione è p1, allora y &amp;gt;= 8 (con questo valore posso soddisfare la richiesta di p1 e in seguito tutte le altre)&lt;br /&gt;
* Se il primo processo della permutazione è p2, allora y &amp;gt;= 5: con questo valore è possibile soddisfare la richiesta di p2; una volta che esso avrà finito, restituirà 3 unità della risorsa B, che permetteranno di soddisfare sia le richieste di A sia quelle di C&lt;br /&gt;
* Se il primo processo della permutazione è p3, allora y &amp;gt;= 8 (ragionamento analogo come per p1)&lt;br /&gt;
&lt;br /&gt;
Volendo scegliere il minimo, y &amp;gt;= 5, ed in conclusione (x, y) &amp;gt;= (6, 5).&lt;br /&gt;
&lt;br /&gt;
''Svolgimento basato in parte sull'approccio di Operating System Concepts di Silberschatz. et al, 9th edition, cap. 7.''&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;
        entry 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;
        entry 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;
        entry 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;
&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;
si, è possibile: &lt;br /&gt;
&lt;br /&gt;
Implementare asend e arecv date bsend e brecv&lt;br /&gt;
&lt;br /&gt;
asend(pid_t, msg_type msg){&lt;br /&gt;
    bsend (&amp;lt;pid_t dst, msg&amp;gt;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
arecv(*){&lt;br /&gt;
  pid_t act = getpid(); \\ act = proprio pid &lt;br /&gt;
  do{&lt;br /&gt;
    &amp;lt;dst, msg&amp;gt; = brecv(*);&lt;br /&gt;
  }while (dst =! act)&lt;br /&gt;
  return msg;&lt;br /&gt;
}&lt;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;
entry 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;
entry 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;
entry 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;
monitor altcolbb {&lt;br /&gt;
&lt;br /&gt;
  generic_type valueBuf[MAX];&lt;br /&gt;
  int front = rear = 0;&lt;br /&gt;
&lt;br /&gt;
  bool isFull = false;&lt;br /&gt;
&lt;br /&gt;
  condition ok2write[2]; //gli indici sono i colori (red=0, blue=1)&lt;br /&gt;
&lt;br /&gt;
  lastColor = None;&lt;br /&gt;
&lt;br /&gt;
  entry void write(color_t color, generic_type val) {&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
        if(isFull)&lt;br /&gt;
          ok2write[color].wait();&lt;br /&gt;
    else&lt;br /&gt;
      if (lastColor == color)&lt;br /&gt;
        ok2write[color].wait();&lt;br /&gt;
              &lt;br /&gt;
    valueBuf[front] = val;&lt;br /&gt;
    front = (front+1) % MAX;&lt;br /&gt;
    lastColor = color;&lt;br /&gt;
&lt;br /&gt;
    if (front == rear)&lt;br /&gt;
      isFull = true;&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-color].signal();&lt;br /&gt;
&lt;br /&gt;
    ok2read.signal();&lt;br /&gt;
        &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  entry generic_type read(void) {&lt;br /&gt;
&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      if (!isFull)&lt;br /&gt;
        ok2read.wait();&lt;br /&gt;
&lt;br /&gt;
    generic_type tmpValue = valueBuf[rear];&lt;br /&gt;
    &lt;br /&gt;
    rear = (rear + 1) % MAX;&lt;br /&gt;
    if (rear == front)&lt;br /&gt;
      isFull = false;&lt;br /&gt;
      color_t tmpColor = lastColor;&lt;br /&gt;
      lastColor = None;&lt;br /&gt;
      ok2write[tmpColor].signal();  //quando un lettore legge l'ultimo elemento&lt;br /&gt;
                                    //dal buffer, ci possono solo essere scrittori&lt;br /&gt;
                                    //in attesa che abbiano lo stesso colore&lt;br /&gt;
                                    //dell'ultimo elemento.&lt;br /&gt;
    else&lt;br /&gt;
      ok2write[1-lastColor].signal();&lt;br /&gt;
      &lt;br /&gt;
    return tmpValue;&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;
&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 c.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
Il programma dispone di una mutex per l'accesso protetto alla variabile n, e dei due semafori s1 ed s2 per regolare l'alternanza tra i thread A e AB. Sulla base di essi, e del fatto che entrambi i thread eseguono 2 cicli, è possibile affermare (verificare) che&lt;br /&gt;
&lt;br /&gt;
* L'alternanza dei due thread è A-AB-A-AB o&lt;br /&gt;
* L'alternanza dei due thread è AB-A-AB-A&lt;br /&gt;
&lt;br /&gt;
Infatti se il thread A svolgesse due cicli consecutivamente, invocherebbe s1.P() due volte senza fare mai ricorso a s1.V() (ragionamento analogo per AB); pertanto è necessario attendere l'intervento dell'altro thread in attesa di una chiamata su s1.V().&lt;br /&gt;
&lt;br /&gt;
Per concludere, i possibili valori di n al termine del programma saranno, in corrispondenza delle due diramazioni elencate sopra&lt;br /&gt;
&lt;br /&gt;
* n = 12&lt;br /&gt;
* n = 5&lt;br /&gt;
&lt;br /&gt;
=== Esercizio g.1 ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente [[User:Acsor|Acsor]] in data 23/08/2020. Ritengo sia: corretto&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&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;
==== Punto b) ====&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;
=== Esercizio g.2 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Verificato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
# Frammentazione interna: allocazioni di pagine la cui dimensione è strettamente maggiore di quella effettivamente richiesta.  Frammentazione esterna: nessuno. Infatti ogni spazio (pagina) allocato e liberato è prima o poi riallocato.&lt;br /&gt;
# Se non viene utilizzato un sistema di caching, una lettura diretta a più blocchi di un file di grandi dimensioni richiede: la lettura della FAT, solitamente posta all'inizio di un [[Glossario#Volume|volume]] (e dunque, su dischi rotazionali, in una traccia differente da quella attuale o da quella del blocco da leggere); la lettura del blocco stesso, e dunque lo spostamento della testina nella traccia e nel settore di interesse&lt;br /&gt;
# Uno scheduling a priorità statica può essere utile ad un processo interattivo, dove è necessario mantenersi all'interno di date soglie temporali o semplicemente svolgere un dato compito con meno ritardo possibile; esempi concreti: un processo che faccia streaming video; un processo appartenente ad un server il cui obiettivo primario è soddisfare le richieste dei propri client il prima possibile, ma dove può anche essere svolta qualche attività dai processi locali (es. programmi applicativi). In uno scheduling a priorità statica, se la presenza di processi ad alte priorità è costante, possono verificarsi indesiderati fenomeni di ''starvation'' nei confronti di processi meno prioritari.&lt;br /&gt;
# ''Domanda puramente nozionistica, la cui risposta può essere ricavata consultando note, lucidi o libri di testo.''&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;
&lt;br /&gt;
=== Esercizio c.1 (da controllare) ===&lt;br /&gt;
&lt;br /&gt;
* Controllato dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
* Controllato dall'utente ? in data ?&lt;br /&gt;
* ...&lt;br /&gt;
&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;
    if (buffer.lenght() &amp;gt;= MAX) {&lt;br /&gt;
        if (waiting_write &amp;gt;= MAX) {&lt;br /&gt;
            buffer.dequeue(); // il valore va perso&lt;br /&gt;
            ok2write.signal();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        waiting_write++;&lt;br /&gt;
        ok2write.wait();&lt;br /&gt;
        waiting_write--;&lt;br /&gt;
    }&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;
    generic_type val;&lt;br /&gt;
&lt;br /&gt;
    if (buffer.lenght() == 0) {&lt;br /&gt;
        if (waiting_read &amp;gt;= MAX)&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;
&lt;br /&gt;
    val = buffer.length() == 0 ? NULL: buffer.dequeue();&lt;br /&gt;
    ok2write.signal();&lt;br /&gt;
&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 ===&lt;br /&gt;
&lt;br /&gt;
* Controllato e corretto dall'utente [[User:Acsor|Acsor]] in data 21/08/2020&lt;br /&gt;
&lt;br /&gt;
==== Punto a) ====&lt;br /&gt;
===== Algoritmo MIN =====&lt;br /&gt;
&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;
===== Algoritmo 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;
==== Punto b) ====&lt;br /&gt;
&lt;br /&gt;
Poiché non è specificato quale dei due algoritmi precedenti applicare, sono state considerate soluzioni per ognuno di essi&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo MIN (da controllare) =====&lt;br /&gt;
(È possibile ottenere una stringa più breve?)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
4 3 2 1 5 3 2 1 4 5 3 2 1 3 2 4 5 1 2 4 3 1 5 4 2 1 3 4   &lt;br /&gt;
-------------------------------------------------------&lt;br /&gt;
4|4|4|4|5|  5  |5|  5  |1|  1  |1|  1  |1|  1  |   1   &lt;br /&gt;
 |3|3|3|3|  3  |3|  3  |3|  3  |5|  5  |5|  5  |   2   &lt;br /&gt;
 | |2|2|2|  2  |2|  2  |2|  2  |2|  2  |3|  3  |   3   &lt;br /&gt;
 | | |1|1|  1  |4|  4  |4|  4  |4|  4  |4|  4  |   4   &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Algoritmo LRU =====&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 1 2&lt;br /&gt;
               Frame 1: 4 4 4 4 5 5 5 5 1 1 1 1 1 1&lt;br /&gt;
               Frame 2:   3 3 3 3 3 3 3 3 5 5 5 5 2&lt;br /&gt;
               Frame 3:     2 2 2 2 2 2 2 2 2 3 3 3&lt;br /&gt;
               Frame 4:       1 1 1 1 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 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;br /&gt;
&lt;br /&gt;
== Esame Pratico 22/01/2016 ==&lt;br /&gt;
http://www.cs.unibo.it/~renzo/so/pratiche/2016.01.22.pdf&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;dirent.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
typedef struct nameNumber {&lt;br /&gt;
        char *name;&lt;br /&gt;
        int value;&lt;br /&gt;
    } nameNumber;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
int prefixToInt (char *string) {&lt;br /&gt;
&lt;br /&gt;
    int i = 0;&lt;br /&gt;
    int num = 0;&lt;br /&gt;
    while (string[i] &amp;gt;= '0' &amp;amp;&amp;amp; string[i] &amp;lt; '9' &amp;amp;&amp;amp; i &amp;lt; strlen(string)) {&lt;br /&gt;
        num = (num*10) + (string[i]-'0');&lt;br /&gt;
        i++;&lt;br /&gt;
    }&lt;br /&gt;
    return num;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void fileSort(struct nameNumber **files) {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int comp (const void * el1, const void * el2) {&lt;br /&gt;
    struct nameNumber *f = *((nameNumber**)el1);&lt;br /&gt;
    struct nameNumber *s = *((nameNumber**)el2);&lt;br /&gt;
    if (f-&amp;gt;value &amp;gt; s-&amp;gt;value) return 1;&lt;br /&gt;
    if (f-&amp;gt;value &amp;lt; s-&amp;gt;value) return -1;&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int arg, char* argv[]) {&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    struct nameNumber **files;&lt;br /&gt;
&lt;br /&gt;
    DIR *dir;&lt;br /&gt;
    struct dirent *ent;&lt;br /&gt;
&lt;br /&gt;
    int count = 0;&lt;br /&gt;
&lt;br /&gt;
    if((dir = opendir(argv[1])) != NULL) &lt;br /&gt;
    {&lt;br /&gt;
        while( (ent = readdir(dir)) != NULL ) &lt;br /&gt;
        {   &lt;br /&gt;
            if (ent-&amp;gt;d_name[0] &amp;lt; '9' &amp;amp;&amp;amp; ent-&amp;gt;d_name[0] &amp;gt;= '0') &lt;br /&gt;
            {&lt;br /&gt;
                files = (struct nameNumber**)realloc(files , (count+1) * sizeof(struct nameNumber*));&lt;br /&gt;
                files[count] = (struct nameNumber*)malloc(sizeof(struct nameNumber));&lt;br /&gt;
                files[count]-&amp;gt;name = (char*)malloc(sizeof(char)*strlen(ent-&amp;gt;d_name) + 1);&lt;br /&gt;
                strcpy(files[count]-&amp;gt;name, ent-&amp;gt;d_name);&lt;br /&gt;
                files[count]-&amp;gt;value = prefixToInt(files[count]-&amp;gt;name);&lt;br /&gt;
                printf(&amp;quot;name : %s  ,  value : %d\n&amp;quot;, files[count]-&amp;gt;name , files[count]-&amp;gt;value);&lt;br /&gt;
                count++;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    qsort(files, count, sizeof(nameNumber*), comp);&lt;br /&gt;
&lt;br /&gt;
    int i;&lt;br /&gt;
    for (i=0; i &amp;lt; count; i++) {&lt;br /&gt;
        printf(&amp;quot;%s\n&amp;quot;,files[i]-&amp;gt;name);&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;
&lt;br /&gt;
== Esame di Concorrenza del 13/01/2005 ==&lt;br /&gt;
Il testo degli esercizi è disponibile alla pagina http://www.cs.unibo.it/~renzo/so/compiti/2005-01-13.con.pdf.&lt;br /&gt;
&lt;br /&gt;
=== Esercizio 1 ===&lt;br /&gt;
Il codice di questo esercizio può essere eseguito scaricando il sorgente Python e l'archivio relativo agli [[Tool_per_semafori_e_monitor|strumenti di concorrenza per il linguaggio Python]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
import threading&lt;br /&gt;
import random&lt;br /&gt;
import time&lt;br /&gt;
from pysm.semaphore import semaphore&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class mod_counter:&lt;br /&gt;
    def __init__(self, mod, start=0):&lt;br /&gt;
        self._mod = mod&lt;br /&gt;
        self._val = start&lt;br /&gt;
&lt;br /&gt;
    def inc(self):&lt;br /&gt;
        self._val = (self._val + 1) % self._mod&lt;br /&gt;
&lt;br /&gt;
    def get(self):&lt;br /&gt;
        return self._val&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class process(threading.Thread):&lt;br /&gt;
    def __init__(self, to_print, c: mod_counter, a, t, r):&lt;br /&gt;
        threading.Thread.__init__(self, name=&amp;quot;proc&amp;quot; + to_print)&lt;br /&gt;
&lt;br /&gt;
        if to_print not in &amp;quot;tar&amp;quot;:&lt;br /&gt;
            raise ValueError(&amp;quot;Unexpected printable character:&amp;quot;, to_print)&lt;br /&gt;
&lt;br /&gt;
        self._counter = c&lt;br /&gt;
        self._x = to_print&lt;br /&gt;
        self._semaphores = {'t': t, 'a': a, 'r': r}&lt;br /&gt;
        self._enter = True&lt;br /&gt;
&lt;br /&gt;
        if self._x == 't':&lt;br /&gt;
            self._semaphores[self._x].V()&lt;br /&gt;
&lt;br /&gt;
    def run(self):&lt;br /&gt;
        while True:&lt;br /&gt;
            self.sync()&lt;br /&gt;
            print(&amp;quot;[%s] %c&amp;quot; % (self.name, self._x))&lt;br /&gt;
&lt;br /&gt;
            # Print a trailing newline&lt;br /&gt;
            if (self._counter.get() == 7):&lt;br /&gt;
                print()&lt;br /&gt;
&lt;br /&gt;
            time.sleep(random.random() * 0.5)&lt;br /&gt;
&lt;br /&gt;
    def sync(self):&lt;br /&gt;
        if (self._enter):&lt;br /&gt;
            self._semaphores[self._x].P()&lt;br /&gt;
            self._enter = False&lt;br /&gt;
        else:&lt;br /&gt;
            self._counter.inc()&lt;br /&gt;
            curr = &amp;quot;taratata&amp;quot;[self._counter.get()]&lt;br /&gt;
&lt;br /&gt;
            self._semaphores[curr].V()&lt;br /&gt;
&lt;br /&gt;
            self._enter = True&lt;br /&gt;
            self.sync()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    counter = mod_counter(8)&lt;br /&gt;
    semaphores = (semaphore(0), semaphore(0), semaphore(0))&lt;br /&gt;
    procs = [process(c, counter, *semaphores) for c in &amp;quot;tar&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.daemon = True&lt;br /&gt;
        p.start()&lt;br /&gt;
&lt;br /&gt;
    for p in procs:&lt;br /&gt;
        p.join()&lt;br /&gt;
&lt;br /&gt;
    return 0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    exit(main())&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Acsor</name></author>
	</entry>
</feed>