UniTO/anno2/YearI/MCAD/lesson11-08112017.md
Francesco Mecca c340eec727 mcad portatil
2019-01-23 12:03:37 +01:00

6.9 KiB

Esercizi

5 filosofi

(slides per implementazione monitor)

Dimostrazione di correttezza

E' necessario dimostrare la correttezza della seguente:

SUM(i from 0 to 4) fork[i] + 2*E = 10

Dove E e' il numero di filosofi che mangiano (hanno fatto takeforks ma non release).

  • Analizzando takeforks, quando un processo esce, aumenta E di 1. Di fatto pero', diminuisco due forks e aumento di 1 E, di modo che l'equaglianza in tesi rimanga valida.

  • Analizzando release, questa si comporta in maniera simmetrica a takeforks: aumenta di 2 forks e diminuisce di 1 E, preservando l'eguaglianza in tesi. La funzione quindi sveglia un altro processo, che riprende da takeforks. Quando questo termina, viene eseguito un altro signal che sveglia un secondo processo.

L'eguaglianza e' sempre valida, essendo che non ci sono condizioni in cui le funzioni creino uno stato invalido.

Molecole d'acqua (monitor)

Il problema e' stato trattato in precedenza con l'utilizzo dei semafori, e' necessario dimostrare la correttezza della soluzione monitor.

(vedi slides per implementazione)

L'invariante in tesi e':

0 <= nH - 2*nO <= 2

Che deve quindi essere sempre vera.

  • Definiamo count(t) = nH(t) - 2*nO(t) dove t e' un qualunque istante durante l'esecuzione del processo.

  • All'inizio, count(0) = 0

  • Dopo una chiamata di stampaH, ho incrementato di 1 nH e count, che quindi rimane valido.

  • Dopo una chiamata di stampaO, pongo count a 0 se count == 2 e' valida. Questo significa:

nH(t) - 2*nO(t) = 2
nH(t) = 2*nO(t) + 2
  • Pertanto, porre count = 0 e' corretto, in quanto sto considerando nO = 0. Il valore massimo di count sara' quindi 2, dato che ogni volta che raggiunge 2 viene resettato.

L'eguaglianza e' quindi dimostrata, in quanto non ci sono condizioni in cui count sia invalido.

Programmazione Concorrente - Modello a Scambio di Messaggi

I processori (fisici o virtuali) hanno una propria memoria privata e quindi utilizzano una rete di comunicazione per interagire (LAN, WAN, architettura monoprocessore con multiplexing CPU (e partizioni di memoria fisse)).

Caratteristiche del sistema

  • Ogni processo puo' accedere unicamente alle risorse allocate nella propria risorsa.
  • Ogni risorsa del sistema e' accessibile ad un solo processo (alla volta).
  • Se una risorsa e' necessaria a piu' processi, bisognera' definire un processo server come gestore della risorsa, che esegue le operazioni richieste dagli altri processi e ritorna i risultati.

Questo modello client-server da luogo a una programmazione concorrente definita centralizzata, opposta alla programmazione concorrente distribuita.

Modello a scambio di messaggi

Aspetti caratterizzanti

Il concetto fondamentale e' quello di canale, ossia collegamento logico tra due processi (pipe). Il nucleo del sistema (kernel, sistema di rete...) deve quindi fornire delle primitive di canali come mezzo di comunicazione tra processi. Il linguaggio di programmazione deve quindi fornire strutture ad alto livello per la gestione delle primitive.

Parametri di un canale

  • Tipologia del canale (direzione flusso dati)

  • Sorgente e destinatario della comunicazione, nonche' la designazione del canale. A seconda del tipo di comunicazione (asimmetrica / simmetrica) puo' essere necessario conoscere solo il destinatario oppure entrambi.

  • Tipo di sincronizzazione adottata tra i processi.

Tipi di canale

  • link: canale simmetrico (uno - uno).

  • port: canale asimmetrico (molti - uno). Questa e' utilizzata per la struttura client-server. Qui, una port e' di proprieta' di un processo server, che e' noto a vari processi client. Il server riceve i messaggi sulla port e li gestisce, fornendo il servizio richiesto. Molto usata a livello kernel (gestione di code, etc)

  • mailbox: canale asimmetrico (molti - molti)

(vedi slides per rappresentazione grafica)

Tipi di sincronizzazione

  • Comunicazione asincrona
  • Comunicazione sincrona (rendez-vous tra processi)
  • Comunicazione con sincronizzazione estesa (come precedente, ma forza la risposta del servizio richiesto). Questa e' la struttura delle cosiddette procedure estese.

Primitive di Comunicazione

  • Dichiarazione di canale asimmetrico molti - uno:
port <tipo> <id> // ex: port int channel1;
  • Invio:
send (<var>) to <port>;
  • Ricezione:
receive(<var>) from <port>;

Nota: port identifica il canale, mentre var e' una variabile dello stesso tipo di port, che e' identificatore di una variabile a cui assegnare il processo.

  • Comandi con guardia:
(<boolean expression>); <primitiva receive>

La guardia e' una tuple di espressione booleana / primitiva receive che viene valutata e puo' fornire diversi valori.

Guardia: valori e funzionamento

  1. guardia fallita: l'espressione booleana e' false
  2. guardia ritardata: l'espressione booleana e' vera, ma bloccata (receive e' bloccante)
  3. guardia valida: l'espressione booleana e' vera e la receive puo' essere eseguita

L'esecuzione di una guardia e' strutturata con una struttura if/else in cui vengono valutate le guardie di tutti i rami, ese ci sono piu' guardie valide, ne viene eseguita una scelta in maniera non deterministica. Se tutte le guardie valide sono ritardate, il processo si sospende in attesa che una delle guardie sia abilitata da un nuovo messaggio. Se non ci sono guardie valide / ritardate, il proceso viene terminato (ma non viene considerato un errore, quindi puo' essere utilizzato similmente al break).

(vedi slides per esempi)

Primitive Asincrone

Comunicazione asimmetrica:

  • send non bloccante
  • receive bloccante

I canali sono definiti mediante il costrutto port.

(vedi slides per esempi) (vedi slides per comparison monitor / messaggi client-server)

Simulazione di un semaforo

E' piu' potente la primitiva semaforica oppure un sistema a scambio di messaggi asimmetrico client / server?

Il passaggio da semafori a scambio di messaggi e' una variante dello schema producer / consumer. Il contrario (scambio di messaggi -> semaforo), illustrato sulle slides, implica la creazione di un processo utilizzando le primitive di scambio di messaggi. Il processo process semaphore sara' quindi l'implementazione contenente due port: port signal P e port signal V, che saranno le uniche operazioni eseguibili sul semaforo. L'atomicita' di P e V, richiesta dalla definizione classica di semaforo, e' da discutere.

  • V e' sicuramente atomica, perche' il semaforo e' l'unico ad avere accesso alle sue risorse (non interrompibile).
  • P e' chiamata da un processo che effettua una richiesta, ed e' costituito da una decrementazione di valore e da una send. Il valore, come per V, e' unico al semaforo, e send non e' interrompibile, pertanto l'implementazione sulle slides e' valida.