# Primitive di comunicazione asincrone Comunicazione asimmetrica: * send non bloccante * receive non bloccante I canali sono definiti mediante un costrutto `port`. *(vedi lesson 11)* E' la primitiva di piu' basso livello, analogamente ai semafori, soprattutto se il kernel non e' in grado di fornire primitive a memoria condivisa. ## Scambio di dati e modello client/server ### Producer and Consumer Data una `port dati`: * Il produttore esegue `send() to dati` * il consumatore esegue `p=receive() from dati` A differenza di produttore e consumatore nel caso di semafori e monitor, **non c'e' controllo sulla dimensione del canale**. Scambio di dati con buffer **potenzialmente infinito**, che pero' potrebbe essere riempito da applicazioni errate. ### Singolo produttore, piu' consumatori *(vedi slides per grafico)* Introduce la necessita' di un processo gestore: * Il produttore manda i dati sulla porta al gestore * I consumatori mandano un segnale **pronto** al gestore, che quindi invia i dati al consumatore attraverso un canale del processo consumatore. *(vedi slides per gestore 'smistatore')* #### Interfaccia produttore ``` produttore { while true { ... produce dato d ... send (d) to gestore.dati } } ``` #### Interfaccia consumatore ``` consumatore { port T dati; . . . send (s) to gestore.pronto p = receive (d) from dati } } ``` ### Piu' produttori, piu' consumatori Caso con **buffer limitato**: * I consumatori sono analoghi al caso precedente * I processi produttori sono multipli, quindi devono segnalare allo smistatore che sono pronti a inviare dati. Il buffer limitato fa si che il gestore debba tenere un contatore per controllare che i produttori possano aggiungere dati al buffer. Il contatore del gestore viene aumentato quando i dati sono inviati dal produttore, e diminuito quando ci sono consumatori che richiedono dati. I consumatori sono quindi autorizzati a ricevere dati solo se il contatore e' `> 0`, mentre i produttori sono autorizzati a mandare dati solo se il contatore e' `< N` (dove N e' la dimensione del buffer). **Questa e' un' applicazione delle guardie**. *(vedi slides per gestore)* #### Interfaccia produttore ``` produttore { port S OK_send; while true { ... produce dato d ... send (s) to gestore.pronto receive (s) from OK_send send (d) to gestore.dati } } ``` ### Problema delle strategie di priorita' Suppongo un server che gestisca un pool di risorse, e client che fanno richieste per ottenere una risorsa e deve ottenerla quello che ha priorita' massima (gli altri si bloccano mentre sono in attesa). *(vedi slides per codice server / esempio di guardie )* Le priorita' non sono specificate: le uniche informazioni sono quelle relative alla priorita' dei processi (il primo in coda e' quello con priorita' massima, l'ultimo quello con priorita' minima). Le risorse sono equivalenti. #### Interfaccia client ``` client { port int risorsa ... send (s) to server.richiesta p = receive (r) from risorsa ... usa risorsa... send (r) to server.rilascio } ``` Il client ha un'interfaccia semplice perche' la priorita' e' tutta gestita dal server. ### Esercizi * l'esercizio 2 e' un crivello di Eratostene (genera tutti i primi filtrando i multipli) * l'esercizio 3 e' un rifacimento dell'esercizio H2O