# Piattaforme e Software per la rete - lezione 7 #### William Fornaciari ###### 13 April 2016 ## Shared Memory Possibilità di creare un segmento di memoria condiviso per far scambiare i dati tra diversi processi. È uno dei modi più veloci per comunicare, ma è pericoloso: può essere necessario controllare i permessi di scrittura. Un alternativa sono i __memory mapped files__: - primitive semplici (stesse dei file) - prestazioni leggermente peggiori Conviene utilizzare i memory mapped files quando una normale scrittura su filesystem non sarebbe abbastanza veloce. L'utilizzo della shared memory consiste in: - il primo processo crea un segmento di memoria e lo inizializza - Altri processi possono accedere al segmento condiviso La primitiva usata per la creazione è `shmget()` e necessita delle librerie 'ipc.h' e 'shm.h' Per poter accedere allo stesso segmento condiviso, i vari processi possono usare la chiave che viene restituita al momento della creazione. Il segmento più piccolo che può essere allocato è 1 pagina, che può valere 1K,4K,... a seconda del sistema. Il terzo parametro è un valore bitwise o flag che serve a dare opzioni o impostazioni di sicurezza, le flag vanno usate in OR per ottenere la sequenza i bit di opzioni finali. La sincronizzazione migliore viene effettuata con i semafori piuttosto che con i permessi, i permessi servono per questioni di sicurezza. Con la primitiva `shmat()` che sta per shared memory attach posso collegare il segmento condiviso ad altri processi. `smhdt()` è un modo per staccare il segmento dal processo chiamante. ### Ciclo di utilizzo di una shared memory Operazioni necessarie: - Creazione del segmento condiviso - Attaccare il segmento a tutti i processi che lo devono usare - Staccare il segmento dai processi che hanno finito di usarlo - Deallorare il segmento una volta che non serve più ## Memory mapped files Diversi processi sono in grado di comunicare con un file condiviso In linux a basso livelli il file viene diviso in pezzi della dimensione delle pagine per avere un acesso ottimizzato. La primitiva usata per questo meccanismo è `mmap()` e dopo la chiamata posso accedere all'oggetto con le primitive dei file Il file dovrebbe sopravvivere al riavvio del computer. La chiamata ad `mmap()` è più flessibile rispetto alle shm ma ha più overhead è possibile caricare in memoria con `mmap()` anche file letti dal filesystem (con le primitive dei file) ## Condivisione di dati attraverso una rete IP __Remote Procedure Call__ è una procedura remota bloccante eseguita nello spazio di memoria della propria macchina Ci sono dei problemi nello scambio di dati, ad esempio può cambiare la endianness tra le due macchine e quindi risulterebbe complicato passare dei puntatori. RPC è stata la soluzione storica (vecchia di 30anni) per le architetture client server rpc si basa su UDP e quindi non garantisce la consegna, in base al valore di ritorno possiamo solo dire che la procedura è stata eseguita almeno una volta, risulta quindi una buona idea fare funzioni *idempotenti*, cioè che produce lo stesso risultato se eseguita più volte. __Remote Procedure Call Messages__ di solito usando __External Data Representation__ che è una codifica indipendente rispetto alle due macchine e che permette di trasferire i dati usando una codifica universale. ### Meccanismo dell' RPC - Programma remoto si registra - Chiamante ottiene il numero di porta - Chiamante codifica i parametri e li invia al remoto - Remoto effettua i calcoli, codifica il risultato e lo invia al chiamante. rpcgen è il compilatore che genera gli stub per server e client. ## Architetture parallele - __Shared memory__ in cui più processori usano una memoria condivisa Caratterizzati da UniformMemoryAccess (UMA), è l'architettura più semplice - __Message passing__ in cui ogni cpu ha una memoria privata consistente rispetto alla memoria condivisa, architettura NotUniformMemoryAccess (NUMA) - __Distributed systems__ in cui i processori comunicano attraverso internet. ### Aspetti HW dei sistemi multiprocessore - Sistemi __UMA__ Possono usare una matrice crossbar oppure una gerarchia di memorie (come le cache) Le architetture UMA funzionano bene per un basso numero di core (<16) La memoria condivisa può essere acceduta tramite un bus, con eventuali cache, i processori posso utilizzare anche una memoria privata per i conti e scrivere il risultato su una memoria condivisa. Le __matrici crossbar__ hanno il problema che il numero di punti cresce esponenzialmente quindi spesso vengono sostituite da switch a strati.