Skip to content

Comunicazione tra processi

La comunicazione tra processi è una funzionalità importante dei sistemi operativi che permette ai processi di scambiare informazioni e dati tra loro. Ci sono diverse tecniche per la comunicazione tra processi, come ad esempio le pipe, i socket e i file condivisi.

Le pipe

Le pipe (o tubi) sono una tecnica di comunicazione tra processi che permette ai processi di scambiare informazioni attraverso un canale unidirezionale. Una pipe consiste in un buffer di memoria condivisa che può contenere dati da inviare da un processo a un altro.

Le pipe possono essere utilizzate per la comunicazione tra due processi in questo modo:

  1. Il primo processo crea una pipe e ne restituisce un’estremità (chiamata “estremità di scrittura”) al secondo processo.
  2. Il secondo processo utilizza l’estremità di scrittura per scrivere i dati nella pipe.
  3. Il primo processo utilizza l’altra estremità della pipe (chiamata “estremità di lettura”) per leggere i dati scritti dal secondo processo.

In questo modo, il secondo processo può inviare informazioni al primo processo attraverso la pipe.

Le pipe sono utili in situazioni in cui due processi devono scambiare informazioni tra loro, ad esempio in un’applicazione client-server o in una pipeline di elaborazione dei dati. Tuttavia, le pipe hanno alcune limitazioni, come il fatto che possono essere utilizzate solo per la comunicazione da un processo all’altro e non viceversa, e che i dati scritti nella pipe devono essere letti nell’ordine in cui sono stati scritti.

I socket

I socket sono una tecnica di comunicazione tra processi che permette ai processi di scambiare informazioni attraverso un canale bidirezionale. Un socket è un punto di accesso a una rete, ovvero un endpoint di comunicazione tra due processi.

I socket possono essere utilizzati per la comunicazione tra due processi in questo modo:

  1. Il primo processo crea un socket e lo lega ad un indirizzo IP e una porta specifica.
  2. Il secondo processo si connette al socket del primo processo utilizzando l’indirizzo IP e la porta specifica.
  3. Una volta stabilita la connessione, i due processi possono scambiare informazioni attraverso il socket in modo bidirezionale.

In Python, il modulo socket fornisce una varietà di funzioni per la creazione e la gestione dei socket. Ecco un esempio di come creare un socket server che accetta connessioni e invia messaggi ai client connessi:

import socket
# Create a socket object
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to an address and port
s.bind(('localhost', 12345))
# Listen for incoming connections
s.listen()
while True:
# Accept a connection from a client
c, addr = s.accept()
print('Got connection from', addr)
# Send a message to the client
c.send(b'Thank you for connecting')
# Close the connection
c.close()

Ecco invece un esempio di come creare un client che si connette al server e riceve il messaggio inviato dal server:

import socket
# Create a socket object
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to the server at localhost on port 12345
s.connect(('localhost', 12345))
# Receive data from the server
data = s.recv(1024)
print(f'Received {data.decode()}')
# Close the connection
s.close()

In questo esempio, il client si connette al server utilizzando l’indirizzo IP localhost e la porta 12345, riceve il messaggio inviato dal server e lo stampa a schermo.

Comunicazione con file condivisi

I file condivisi (o file shared memory) sono una tecnica di comunicazione tra processi che permette ai processi di scambiare informazioni attraverso un’area di memoria condivisa. In pratica, i processi possono accedere alla stessa porzione di memoria e leggere o scrivere dati in modo sincronizzato.

I file condivisi possono essere utilizzati per la comunicazione tra due processi in questo modo:

  1. Il primo processo crea un file condiviso e ne restituisce il descrittore.
  2. Il secondo processo apre il file condiviso utilizzando il descrittore fornito dal primo processo.
  3. Entrambi i processi possono ora leggere o scrivere dati nel file condiviso.

In Python, la libreria mmap fornisce funzioni per l’accesso ai file condivisi. Ecco un esempio di come creare un server che scrive in un file condiviso e un client che legge da esso:

import mmap
# Server code
def server():
# Create a shared memory file of size 1024 bytes
f = open('shared_file', 'w+b')
f.write(b' ' * 1024)
f.seek(0)
# Map the file into memory and return the memory object
mem = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_WRITE)
# Write data to the shared memory
mem.write(b'Hello client!')
# Client code
def client():
# Open the shared memory file in read mode
f = open('shared_file', 'rb')
f.seek(0)
# Map the file into memory and return the memory object
mem = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
# Read data from the shared memory
data = mem.read(12)
print(f'Received {data.decode()}')
# Run server and client functions in separate threads
import threading
t_server = threading.Thread(target=server)
t_client = threading.Thread(target=client)
t_server.start()
t_client.start()
t_server.join()
t_client.join()

In questo esempio, il server crea un file condiviso di dimensione 1024 byte e scrive i dati “Hello client!” in esso. Il client apre lo stesso file condiviso in modalità di sola lettura e legge i dati scritti dal server. Entrambi i processi utilizzano la libreria mmap per accedere al file condiviso.

Nota che in questo esempio il file condiviso viene creato e aperto con il nome “shared_file”. Assicurati di utilizzare lo stesso nome per entrambi i processi o di modificare il codice per adattarsi alle tue esigenze.

comunicazione mediante code di messaggi

comunicazione tra processi

In Python, il modulo multiprocessing fornisce un’interfaccia per la creazione e la gestione dei processi e per la comunicazione tra di loro. Ad esempio, è possibile utilizzare una Queue per far comunicare due processi. Ecco un esempio:

from multiprocessing import Process, Queue
def fun1(q):
q.put([4, 'hello from function 1'])
def fun2(q):
print(q.get())
if __name__ == '__main__':
q = Queue()
p1 = Process(target=fun1, args=(q,)))
p2 = Process(target=fun2, args=(q,)))
p1.start()
p1.join()
p2.start()
p2.join()

In questo esempio, vengono creati due processi p1 e p2 che eseguono rispettivamente le funzioni fun1() e fun2(). La funzione fun1() inserisce un elemento nella coda q, mentre la funzione fun2() stampa l’elemento presente in testa alla coda q. In questo modo, i due processi comunicano attraverso la coda q.

In generale, la comunicazione tra processi può essere utilizzata per implementare una varietà di applicazioni, come ad esempio il calcolo distribuito o la gestione di un sistema operativo in multitasking. Ad esempio, nel calcolo distribuito, i processi possono scambiare informazioni tra loro per suddividere il carico di lavoro e accelerare i tempi di esecuzione dell’applicazione. Nella gestione di un sistema operativo in multitasking, la comunicazione tra processi può essere utilizzata per coordinare l’esecuzione di più compiti contemporaneamente. La comunicazione tra processi è un concetto fondamentale nell’ambito della programmazione parallela e del multiprocessing. Le diverse modalità di comunicazione tra processi, verranno poi scelte per essere utilizzate a seconda delle esigenze dell’applicazione.

Scelta del meccanismo di comunicazione tra processi

Ecco uno schema generale dei criteri di scelta delle metodologie di comunicazione tra processi:

  1. Tipo di informazione da scambiare: alcune informazioni possono essere scambiate più facilmente attraverso una modalità di comunicazione rispetto ad altre. Si pensi ad un testo piuttosto che una immagine.
  2. Numero di processi coinvolti: alcune modalità di comunicazione sono più adatte per un numero maggiore o minore di processi coinvolti.
  3. Necessità di sincronizzazione: alcune modalità di comunicazione richiedono una sincronizzazione più stretta tra i processi rispetto ad altre.
  4. Velocità di trasmissione: alcune modalità di comunicazione sono più veloci di altre per la trasmissione delle informazioni.
MetodologiaTipo di informazioneNumero di processiNecessità di sincronizzazioneVelocità di trasmissione
Coda di messaggi (FIFO)sempliceAltoBassaAlta
Variabili condiviseMediaBassoAltaBassa
SocketComplessaBassoBassaAlta

Ecco un algoritmo in pseudocodice che guidi nella scelta della metodologia di comunicazione tra processi:

Funzione scegli_metodologia_comunicazione(tipo_informazione, numero_processi, necessita_sincronizzazione, velocita_transmissione):
se tipo_informazione = semplice allora
return coda_messaggi
altrimenti se numero_processi = alto allora
return variabili_condivise
altrimenti se necessita_sincronizzazione = alta allora
return socket
altrimenti
return coda_messaggi
Fine funzione

Nota che questo algoritmo è solo un esempio di come si potrebbe scegliere la metodologia di comunicazione tra processi in base ai criteri elencati. Potrebbero esserci altri fattori da considerare a seconda delle esigenze dell’applicazione.