Comunicazione tra processi
# Comunicazione tra processi

In informatica l'espressione comunicazione tra processi (in inglese inter-process communication o IPC) si riferisce a tutte quelle tecnologie software il cui scopo è consentire a diversi processi di comunicare tra loro scambiandosi dati e informazioni. I processi possono risiedere sullo stesso computer o essere distribuiti su una rete. Tutti i sistemi operativi multitasking forniscono qualche meccanismo fondamentale di IPC; altri meccanismi più sofisticati o orientati a particolari tipi di sistemi software possono essere forniti da tecnologie middleware, linguaggi di programmazione o a livello applicativo, basandosi sui meccanismi forniti dal sistema operativo. In modo equivalente, questi metodi vengono utilizzati per la gestione dei thread.

## Descrizione

Nel caso specifico di processi distribuiti, i meccanismi di comunicazione fra processi sono in effetti protocolli di rete. Si deve notare, tuttavia, che non tutti i protocolli di rete sono meccanismi di IPC; ai livelli bassi della gerarchia ISO/OSI, infatti, il concetto di processo non compare, e i protocolli si limitano a farsi carico del trasferimento di dati fra computer. L'esempio forse più noto di protocollo di rete per lo scambio di informazioni fra processi è TCP; per un esempio di IPC a livello di linguaggio di programmazione si pensi a RMI di Java. Di norma, i meccanismi di IPC per processi distribuiti permettono la comunicazione anche fra processi residenti sulla stessa macchina.

Altri esempi vari di meccanismi utilizzabili per l'IPC includono i socket Unix, le porte del kernel Mach, il middleware CORBA, e la tecnologia Component Object Model di Microsoft.

In senso lato si può intendere come meccanismo di comunicazione fra processi anche la semplice clipboard che consente a un utente di copiare e incollare informazioni da una finestra a un'altra, o l'uso di file, che un processo scrive e un altro legge; tuttavia, si parla di IPC in senso stretto solo per quei meccanismi che possono essere usati dal software senza intervento manuale umano e che non memorizzano i dati su memorie di massa.

Tabella (non esaustiva) di tecnologie e paradigmi di IPC:

| Metodo | Sistemi operativi o altri ambienti in cui è disponibile |
| - | - |
| Segnale | Tutti i sistemi POSIX |
| Pipe anonima | Tutti i sistemi POSIX e Microsoft Windows |
| Pipe con nome | Tutti i sistemi POSIX e Microsoft Windows |
| Scambio di messaggi (nessuna condivisione) | Viene usata nel paradigma MPI, nell'RMI di Java, in CORBA e altri |
| Semaforo | Tutti i sistemi POSIX e Microsoft Windows |
| Memoria condivisa o File mappato in memoria (MMF) | Tutti i sistemi POSIX e Microsoft Windows |
| Coda di messaggi | Molti sistemi operativi |
| Chiamata di procedura remota (RPC) | Molti sistemi operativi |
| Mailbox | Molti sistemi operativi |
| Socket | Tutti i sistemi operativi con supporto di rete |

### Sequenzialità e non sequenzialità

Nelle situazioni più semplici l'avanzamento dei processi avviene in maniera sequenziale cioè, il sistema operativo assegna ad ogni processo le risorse necessarie per portare a termine il lavoro. Si parla di non sequenzialità quando i processi sono più complessi e bisogna suddividere il processo principale in sotto-processi più semplici da elaborare. Generalmente i sistemi operativi operano nell'ottica non sequenziale. È bene però accennare che tali processi possono effettuare delle comunicazioni attraverso lo scambio di informazioni e di eseguire le diverse operazioni in modalità parallela. Esistono poi situazioni in cui i processi entrino in competizione per l'utilizzo di una risorsa, creando così delle esecuzioni concorrenti. Tali situazioni vengono gestite dal sistema operativo tramite alcune primitive situate nel kernel e in particolare dal gestore dei processi (Scheduler).

### Scambio di informazioni

Al livello base della comunicazione tra processi si presenta la possibilità dello scambio di informazioni tra due o più processi. Tale opzione viene realizzata attraverso due primitive:

* Send: che consente l'invio dell'informazione
* Receive: che consente di ricevere le informazioni

Un esempio tipico di comunicazione tra processi in rete viene presentato nell'architettura client/server, le routine usate per lo scambio di informazioni sulla rete prendono il nome di socket.

## Elaborazione

L'elaborazione dei processi viene suddivisa in due modalità:

* la modalità parallela
* la modalità concorrente

### Elaborazione parallela

L'elaborazione parallela dei processi consiste nell'eseguire interi processi o parti di essi in modalità parallela. Il sistema operativo può richiedere l'esecuzione di uno o più processi mentre un altro processo è in fase di esecuzione. I diversi processi che vengono lanciati in esecuzione prendono il nome di Coroutine, segnalano il completamento dell'esecuzione attraverso la primitiva Resume e cedono il controllo ad un'altra Coroutine. Quando un processo avanza in un punto in cui può essere avviata l'esecuzione di un altro processo in maniera parallela rispetto al primo, il sistema operativo attraverso la primitiva fork , genera un processo figlio che avanza in maniera indipendente dal padre. Il processo padre continua la sua esecuzione fin quando non incontra la primitiva join che controlla lo stato di avanzamento del processo figlio. Un'altra forma di elaborazione parallela riguarda la possibilità che all'interno di uno stesso processo possano essere lanciate in esecuzione diverse istruzioni in modo parallelo, tale esecuzione viene realizzata attraverso le primitive Cobegin e Coend.

### Elaborazione concorrente

Viene definita elaborazione concorrente quando due o più processi accedono alle stesse risorse oppure quando la terminazione di un processo consente l'avanzamento di un altro processo. Tale elaborazione può causare diversi problemi al sistema se non viene gestita in maniera adeguata, infatti il sistema operativo svolge una funzione molto importante per risolvere le problematiche riguardante questo tipo di elaborazione. Attraverso la sincronizzazione dei processi il sistema operativo risolve queste problematiche. In pratica il sistema operativo (l'os) impedisce che i processi entrino in conflitto tra di loro, gestendo l'accesso dei processi alle risorse ed evitando che i processi blocchino l'avanzamento complessivo dell'unità di elaborazione. In tale ambito il sistema operativo garantisce la protezione della aree di lavoro dei processi ed evita l'interferenza tra questi ultimi, evitando così perdite di dati.

**Produttore consumatore**

È possibile che due processi operino in modalità concorrente ma non entrino in conflitto tra loro. Uno schema tipo di tale modalità è quello del Produttore/Consumatore. Il processo Produttore elabora i risultati necessari per l'avanzamento del processo Consumatore e il processo Consumatore non può proseguire se i risultati del primo non vengono resi disponibili. Per operare in questa modalità i processi accedono ad un'area di lavoro condivisa da entrambi chiamata buffer. In questa locazione di memoria il processo produttore inserisce i dati ed il processo consumatore controlla il contenuto del buffer per verificare la disponibilità dei dati richiesti. Più complesso è il caso in cui i processi entrino in competizione per l'uso delle risorse del sistema di elaborazione, l'avanzamento di un singolo processo può avvenire solo quando uno dei due processi viene escluso nell'accesso ad una determinata risorsa. Questo metodo di elaborazione prende il nome di Mutua Esclusione (Mutex).

**Semaforo**

Il semaforo è un meccanismo fondamentale per la sincronizzazione dei processi in concorrenza nell'uso delle risorse e la mutua esclusione. In pratica il semaforo non è altro che una variabile allocata all'interno della memoria di lavoro del sistema operativo, in cui il valore viene alterato da un qualsiasi processo. I valori assunti da questa variabile possono essere binari cioè, 0/1 oppure valori naturali. In base al valore assunto dalla variabile il processo può accedere ad una risorsa oppure trovare un valore che indica l'uso della risorsa da parte di un altro processo, quindi il processo dovrà attendere un determinato intervallo di tempo per testare nuovamente la variabile semaforo. I processi che usano le varie risorse, alterano il valore della variabile semaforo in maniera tale da indicare ai successivi processi l'uso di una determinata risorsa. Di solito i semafori possono essere utilizzati per condividere aree di memoria o per consentire a più processi l'accesso ai file. I semafori vengono spesso utilizzati quando i processi entrano nelle sezioni critiche, cioè quando i processi vanno in conflitto tra di loro o accedono contemporaneamente alle risorse.

**Semaforo**

**Primitive segnala e attendi**

Le primitive usate dai semafori sono:

* la primitiva Attendi
* la primitiva Segnala

La primitiva Attendi indica il tempo necessario prima di entrare nella sezione critica. Il semaforo gestisce gli ingressi dei processi all'interno della sezione critica e la modifica del proprio valore, in maniera tale da impedire ad altri processi di accedere a quella determinata risorsa.

* Pseudocodice di Attendi:

La primitiva Segnala indica che il processo ha terminato la sezione critica e azzera il valore della variabile semaforo.

* Pseudocodice di Segnala:

**Semaforo**

**Blocco critico**

Il blocco critico o deadlock si verifica quando uno o più processi rimangono indefinitamente in stato di attesa, a causa del non verificarsi delle condizioni necessarie per loro proseguimento. L'uso del semaforo impedisce il verificarsi del blocco critico. Due o più processi si trovano in un blocco critico quando si verificano tali condizioni:

* le risorse non condivisibili: mutua esclusione tra i processi sull'uso delle risorse.
* possesso ed attesa: un processo in possesso di una risorsa ne richiede l'utilizzo di un'altra utilizzata da un altro processo.
* attesa circolare: gestione delle risorse ristrette ad un insieme di processi
* prelazione impossibile: una risorsa quando viene assegnata ad un certo processo non può essere utilizzata da altri processi.

Il gestore dei processi ha il compito di risolvere i blocchi critici attraverso diverse modalità:

* Prevenzione delle situazioni di stallo.
* Controllo sull'avanzamento dei processi, rilevazione ed eliminazione dei blocchi critici.
* Rilevazione preventiva delle fasi di stallo attraverso opportune primitive.
