SlideShare una empresa de Scribd logo
1 de 26
Descargar para leer sin conexión
Linux Internals:
Multiprocessing, Multithreading e
           Asincronia
Come aumentare le prestazioni parallelizzando
                Sebastiano Merlino
           merlino.sebastiano@gmail.com
Perch´ parallellizzare?
                                     e

Migliora le prestazioni del programma (mentre un processo ` in
                                                           e
attesa per esempio in fase di I/O, un altro pu` lavorare).
                                              o
Migliora la distribuibilit` del programma (rendendolo pronto per
                          a
la scalabilit` orizzontale).
             a
` spesso vitale e necessario (come nel caso delle interfaccie
E
grafiche).
`
E utile a volte persino in termini di modularit` e leggibilit` del
                                               a             a
codice.
Multiprocessing
Con multiprocessing, in questo contesto, intendiamo
l’esecuzione di multipli processi software concorrenti che
abbiano spazi di memoria indipendenti.
I processi su Linux proliferano mediante meccanismo di
generazione. Il processo di sistema operativo che si occupa della
generazione di tutti i processi kernel necessari ` init. Ogni
                                                 e
processo ` identificato da un PID univoco.
          e
Il meccanismo scelto su linux per la generazione di nuovi
processi ` la cosiddetta fork utilizzando la quale un processo
         e
sdoppia il proprio spazio di indirizzi in memoria permetterndo
l’esecuzione di un nuovo processo che sfrutti questa copia.
Fork
      La funzione fork (int fork()) trasforma un singolo processo in
      esecuzione in due processi identici, noti come parent e child.
      Quando l’esecuzione ha successo, la fork ritorna 0 al processo
      child e il PID del child al processo parent.
    #include <unistd.h>
    #include <stdio.h>

    int main() {
    int cpid = fork();
        if(cpid > 0) {
            printf("I am the father and this is my child: %dn", cpid);
        } else if (cpid == 0) {
            printf("I am the childn");
        } else {
            printf("Error!");
        }
}
Meccanismi di IPC

`
E spesso necessario rendere possibile ai processi creati il
comunicare fra loro.
I sistemi di IPC (Inter-process communication) che Linux
fornisce sono svariati:
    Pipe (< stdio.h >)
    Signal (< signal.h >)
    Message Queues (< sys/msg .h >)
    Semaphores (< sys/sem.h >)
    Shared Memory (< sys/shm.h >)
    Socket (< sys/socket.h >)
Pipe
Le Pipe sono oggetti grazie ai quali l’output di un processo pu`
                                                               o
essere iniettato in input ad un altro processo.
Linux fornisce due modi di definire pipe:
 1. FILE* popen(char* command, char* type) - apre una pipe
    ove command ` il processo con il quale ci vogliamo connettere.
                    e
    Il tipo pu` essere “r” in lettura o “w” in scrittura. Le pipe cos`
              o                                                      ı
    aperte vanno chiuse tramite pclose(FILE* fs) e vengono
    scritte/lette tramite l’utilizzo di fprintf e fscanf.
 2. int pipe(int fd[2]) - crea una pipe restituendo due file
    descriptor. fd[0] ` aperto in lettura ed fd[1] ` aperto in
                      e                              e
    scrittura. Le pipe vanno sempre chiuse mediante metodo
    close(int fd). Vengono sfruttati i metodi read e write.
#include <signal.h>
#include <stdio.h>

int main() {
    int pdes[2];
    pipe(pdes);
    if(fork() == 0) {
        char received_message[10];
        close(pdes[1]);
        read(pdes[0], (void*) received_message, 9);
        printf("message received: %sn", received_message);
    } else {
        close(pdes[0]);
        write(pdes[1], (void*) "Hello!", 7);
        printf("message sent: Hello!n");
    }
    return 0;
}
Signal
I segnali sono interrupt generati via software che possono essere
inviati ad un processo per segnalargli che ` avvenuto un evento.
                                             e
I segnali possono essere generati in maniera sincrona, ma sono
genealmente meccanismi asincroni. Essi sono identificati
univocamente da un numero intero compreso tra 0 e 31.
Due sono i modi pi` comuni per l’invio di un segnale:
                      u
     int kill(int pid, int signal) - ` una chiamata di sistema che
                                      e
     permette di emettere un segnale. Se il pid ` maggiore di zero, il
                                                    e
     processo da esso identificato sar` l’unico destinatario; nel caso
                                        a
     in cui il pid sia zero, il messaggio sar` inviato a tutti.
                                             a
     int raise(int signal) - invia un messaggio al processo running.
     Utilizza kill in maniera trasparente ponendo come pid quello del
     processo che la esegue.
Signal

Un’applicazione pu` definire una funzione cosiddetta che verr`
                    o                                         a
invocata quando uno specifico segnale viene ricevuto.
L’handler per i segnali viene definito tramite la chiamata int
(*signal(int sig, void (*func)()))(); ricevuto il segnale
identificato da sig, la funzione func verr` invocata. func pu`
                                         a                  o
assumere tre valori:
    SIG DFL - funzione di default; il processo sar` terminato una
                                                  a
    volta ricevuto il segnale
    SIG IGN - funzione ignore; il segnale verr` catturato ed ignorato
                                              a
    un generico puntatore a funzione.
#include <stdio.h>
#include <signal.h>

void sigproc(void);

void quitproc(void);

main()
{ signal(SIGINT, sigproc);
 signal(SIGQUIT, quitproc);
 printf(‘‘ctrl-c disabled use ctrl-$backslash$$backslash$ to quit$backslash$n’’);
 for(;;); /* infinite loop */}

void sigproc()
{   signal(SIGINT, sigproc); /* */
 /* NOTE some versions of UNIX will reset signal to default
 after each call. So for portability reset signal each time */

 printf(‘‘you have pressed ctrl-c $backslash$n’’);
}

void quitproc()
{   printf(‘‘ctrl-$backslash$$backslash$ pressed to quit$backslash$n’’);
 exit(0); /* normal exit status */
}
Message Queues
Le code di messaggi si basano su uno schema molto semplice.
Un processo piazza un messaggio all’interno di una struttura
(una coda) fornita dal sistema operativo. Un altro processo,
conoscendo l’identificativo della coda da cui leggere potr`a
successivamente recuperare il messaggio.
Una coda di messaggi pu` essere inizializzata mediante il
                          o
metodo int msgget(key t key, int msgflg); il metodo ritorna
l’identificativo univoco della coda - i parametri specificati
rappresentano il nome assengato alla coda e dei flag utili per il
management dei diritti.
Un messaggio viene inserito nella coda tramite il metodo
msgsnd e viene invece recuperato mediante msgrcv.
Semaphores
I semafori costituiscono un fondamentale sistema di coordinamento
tra processi.
Qualora due o pi` processi condividano la stessa risorsa mediante
                 u
meccanismi di IPC ` vitale che l’accesso a tale risorsa sia
                    e
correttamente gestito (osserveremo meglio questo problema nella
parte dedicata ai thread).
Un semaforo viene inizializzato (o se ne ottiene accesso) tramite: int
semget(key t key, int nsems, int semflg); ove, key rappresenta un
nome associato all’id univoco che la funzione ritorna; nsems indica il
numero di semafori che si vogliono ottenere e semflg sono i flag di
gestione assegnati al semaforo.
Operazioni sul semaforo vengono eseguite mediante la direttiva int
semop(int semid, struct sembuf *sops, size t nsops);
Shared Memory
La shared memory rappresenta il metodo, forse pi` veloce di scambiare dati fra
                                                    u
processi differenti. In sostanza, un processo crea un’area di memoria alla quale
altri processi possono accedere (se viene loro dato diritto). Questo metodo si
porta ovviamente dietro il problema della condivisione di una risorsa e pertanto
porta all’insorgenza della necessit` di sincronizzare l’accesso da parte dei processi
                                   a
alla memoria condivisa.
Un segmento di memoria condivisa ` acceduto tramite int shmget(key t key, size t
                                 e
size, int shmflg);
Per potere usare la memoria condivisa, il processo deve farne attach al suo spazio
di indirizzi; questo viene fatto tramite void *shmat(int shmid, const void
*shmaddr, int shmflg); che ritorner` in shmaddr l’indirizzo alla head della
                                      a
memoria condivisa.
Il processo rilascia l’accesso tramite int shmdt(const void *shmaddr);
Trascuro per ora le problematiche di sincronizzazione, essendo queste simili per
molti versi a quelle successivamente trattate nella parte dedicata ai thread.
Socket
Le Socket costituiscono un sistema di IPC punto-punto e bidirezione. Pur
non essendo il sistema pi` veloce di comunicazione, la loro versatilit` e la
                           u                                          a
possibilit` di usarle attraverso la rete le rendono molto usate.
          a
Esistono 4 tipi di socket:
     Stream Socket (SOCK STREAM) - bidirezionali, sequenziali, affidabili
     e non duplicati senza limiti di trasmissione. Usa TCP.
     Datagram Socket (SOCK DGRAM) - bidirezionali, non assicurano
     l’ordine dei messaggi che sono costituiti da pacchetti di dimensione
     finita. Non necessita di connessione. Usa UDP
     Sequential Packet Socket (SOCK SEQPACKET) - essenzialmente un
     Datagram ma sequenziale, affidabile e con connessione. Mai
     implementato.
     Raw - utilizza direttamente i protocolli di comunicazione.
Socket
Le Socket vengono create mediante la funzione int socket(int domain, int type, int
protocol) (se il protocollo non ` specificato esso sar` il default per il tipo). Le Socket si
                                  e                    a
collegano le une alle altre tramite indirizzi. Per assegnare un indirizzo ad una socket si
usa il metodo int socket(int domain, int type, int protocol).
Le connessioni tramite Socket sono solitamente non bilanciate (client-server). Il server
(in una connessione STREAM) chiama int listen(int s, int backlog) ove backlog
rappresenta il numero massimo di connessioni da accodare.
Il client per collegarsi al Server chiamer` int connect(int s, struct sockaddr *name, int
                                          a
namelen) e, infine, il server, per accettare la connessione eseguir` int connect(int s,
                                                                    a
struct sockaddr *name, int namelen) che restituisce il file descriptor di una socket
dedicata esclusivamente alla connessione.
In una socket stream, la ricezione e l’invio dei messaggi sono eseguiti mediante i metodi
read() e write() o, alternativamente, recv(...) e send(...).
In una socket datagram, invece si usano i metodi sendto() e recvfrom() o, in alternativa,
recvmsg() e sendmsg.
Soluzioni differenti - OpenMP
OpenMP ` una API che supporta il multiprocessing con memoria condivisa.
           e
La semantica della libreria ` cos` semplice da farla apparire quasi come una funzionalit` del linguaggio.
                             e    ı                                                     a
La libreria si occupa in maniera del tutto trasparente per il programmatore del partizionamento dei dati e della
distribuzione tra i core del codice.

#include <stdio.h>

int main(void)
{
  #pragma omp parallel
    printf("Hello, world.n"); // Verr` stampato una volta per ogni processore
                                      a
  return 0;
}

int main(int argc, char *argv[]) {
    const int N = 100000;
    int i, a[N];

    #pragma omp parallel for // k cicli saranno eseguiti in parallelo (con k numero di processori)
    for (i = 0; i < N; i++)
        a[i] = 2 * i;

    return 0;
}
Multithreading
Possiamo considerare un Thread come un lightweight Process.
L’utilizzo di soluzioni multithread ha grandi benefici:
    Aumenta la responsivit` - in presenza di GUI, ad esempio,
                          a
    permette di dedicare un thread ad ogni attivit` grafica.
                                                  a
    Usa in maniera pi` efficiente i sistemi multiprocessore - ` pi`
                        u                                     e u
    facile scalare rispetto al numero di processori applicazioni
    multithread.
    Migliora la struttura di programma - molti programmi risultano
    meglio strutturati come sistemi a parti semi-indipendenti che
    come monoliti.
Confronto tra Multiprocessing e
                                      Multithreading
I benefici dei thread rispetto ai processi consistono essenzialmente in:

    minor tempo per essere creati (dato che sfruttano l’address
    space senza copiarlo)
    minor tempo per essere terminati
    minor tempo per switchare da un thread ad un altro (rispetto a
    quello richiesto per switchare da un processo all’altro)
    minore overhead dovuto alla comunicazione
Il vantaggio dei processi sui thread `, invece rappresentato da un
                                     e
maggior livello di isolamento.
Pthreads
La libreria pi` importante per la realizzazione di codice
              u
multithread ` libpthread (pthread.h).
              e
Per creare un thread si usa int pthread create(pthread t *tid,
const pthread attr t *tattr, void*(*start routine)(void *),
void *arg); - se non si passano attributi, il thread sar` non
                                                        a
detachato e erediter` la priorit` del padre.
                    a           a
La libpthread ` parecchio complessa e contiene molti metodi
              e
per la gestione e l’inizializzazione dei thread dei quali non
tratteremo qui (creare variabili thread local, gestione priorit`,
                                                               a
ecc...).
Sincronizzazione

La libpthread offre anche vari meccanismi di sincronizzazione fra i
thread. La sincronizzazione in questo caso ` vitale poich´ i thread
                                           e             e
condividono lo stesso spazio di indirizzi.
    Mutual exclusion locks (Mutex)
    Condition variable attributes
    Semaphores (non li tratteremo in quanto molto simili a quelli
    visti per i processi)
Sincronizzazione
                                                         Mutex
I mutex rappresentano un sistema molto diffuso di serializzazione delle
operazioni; essi sincronizzano i thread serializzando l’accesso a
porzioni del codice definite sezioni critiche.
Un mutex viene creato tramite le funzione int
pthread mutex init(pthread mutex t *mp, const
pthread mutexattr t *mattr); - ove il passaggio degli attributi ` del
                                                                e
tutto arbitrario.
Esistono mutex di varia natura (unici, condivisi, scoped, ecc...) e, le
varie tipologie, se non fornite in libreria, sono facilmente realizzabili.
I mutex vengono lockati e slockati rispettivamente tramite le funzioni
pthread mutex lock e pthread mutex unlock.
Sincronizzazione
                                                        Condition Variables
      Le Condition Variables sono usate per bloccare atomicamente un thread finch´ un  e
      determinato evento non si verifica; esse sono sempre utilizzate in congiunzione con
      Mutex e lock. Si controlla la condizione dopo avere acquisito il lock e, nel caso
      questa non sia verificata ci si mette in wait sulla condizione mentre atomicamente
      si rilascia il lock. Quando un altro thread cambia la condizione e notifica il cambio
      si riacquisisce il lock e si rivaluta la condizione.
      Le Condition Variables sono inizializzate cos` int
                                                       ı
      pthread cond init(pthread cond t *cv, const pthread condattr t *cattr);
      Varie versioni del metodo wait (semplice, temporizzata, ecc...) possono essere
      usate per attendere che la condizione si verifichi
      La condizione pu` essere segnalata mediante: int
                          o
      pthread cond signal(pthread cond t *cv);.
      Il modo corretto di mettersi in attesa su una condition variable ` il seguente:
                                                                       e
pthread_mutex_lock();

while(condition_is_false) // previene Spurious WakeUp
  pthread_cond_wait();
pthread_mutex_unlock();
Moderne Amenit`
                                                          a

Negli anni, molte altre librerie che abilitano il multithreading sono
nate. Fra queste ritroviamo:
     boost::thread - contiene tutti i maggiori paradigmi di gestione
     dei thread e della loro sincronizzazione
     Qt - dispone di versioni ad alto livello di trasparenza delle
     funzionalit` fin qui esposte
                a
Asincronia
Risulta spesso utile non assegnare specificatamente un job ad un
thread ma mantenere un pool di thread detti workers ed assegnare ad
uno di essi un job solo quando si verifichi uno specifico evento che lo
richieda. Quest’idea ` alla base dei pattern reactor e proactor.
                      e
Un sistema di questo tipo ` detto asincrono in quanto si oppone al
                            e
classico meccanismo sincrono basato su loop e polling o wait su
condition variable in cui un job ` assegnato sempre e solo ad un
                                 e
thread (nel quale quindi, per ogni job viene creato un nuovo thread).
Questo sistema ` vincente in quanto ottimizza le prestazioni del
                 e
programma sia in termini di cicli eseguiti che in termini di memoria
occupata; tra l’altro esso rende la quantit` di risorse necessarie al
                                           a
programma prevedibile in ogni momento e non strettamente
dipendente dagli input.
Asincronia
Un problema molto sentito ` quello della gestione multithread di un
                            e
sistema Thread che riceve richieste da vari client. Se le richieste
fossero servite sequenzialmente, non sarebbe possibile gestire richieste
concorrenti.
La prima soluzione che ci viene in mente ` quella di creare un thread
                                           e
per ciascuna richiesta ricevuta. In questo modo sicuramente riceviamo
il problema di gestione ma si presenta un nuovo problema. Se, infatti,
ricevessimo nello stesso istante una gran quantit` di richieste, eg.
                                                   a
10000, avremmo uno spawn istantaneo di 10000 thread che potrebbe
portare al kill del nostro processo da parte del sistema operativo.
La soluzione a questo problema (peraltro noto come c10k problem) si
basa proprio su meccanismi asincroni come quelli descritti
precedentemente; molti di questi si basano sull’utilizzo di select e
poll.
select e poll
select e poll sono potenti strumenti per il multiplexing delle socket. Un
programmatore pu` usare questi strumenti per scoprire quando un evento di
                    o
scrittura sia avvenuto su una socket cos` da comprendere che ` il momento
                                           ı                      e
di leggere.
La select funziona come segue: int select(int nfds, fd set *readfds, fd set
*writefds, fd set *errorfds, struct timeval *timeout); ove nfds ` il fd di
                                                                      e
valore pi` alto, readfds, writefds e errorfds sono dei set di file descriptor da
         u
controllare e timeout ` un eventuale timeout che scatta qualora non
                       e
avvengano eventi su nessun file descriptor. La funzione torna il numero di
fd su cui ` avvenuto un evento e riempie i set con solo i file descriptor su
          e
cui sono avvenuti eventi.
La poll ` un’evoluzione della select che ne migliora essenzialmente la
        e
semantica. Essa permette di specificare il tipo di eventi su cui porsi in
ascolto (oltre a supportare un numero maggiore di eventi). Ad oggi poll() `    e
deprecata e sarebbe bene usare la nuova versione detta epoll().

Más contenido relacionado

La actualidad más candente

Pycrashcourse3.0
Pycrashcourse3.0Pycrashcourse3.0
Pycrashcourse3.0rik0
 
Linux Day 2014 - Napoli - Programma Il Futuro: una scelta open source
Linux Day 2014 - Napoli - Programma Il Futuro: una scelta open sourceLinux Day 2014 - Napoli - Programma Il Futuro: una scelta open source
Linux Day 2014 - Napoli - Programma Il Futuro: una scelta open sourceMario Rossano
 
LinuxDay 2004 - Linux - Storia e caratteristiche vincenti - slides
LinuxDay 2004 - Linux - Storia e caratteristiche vincenti - slidesLinuxDay 2004 - Linux - Storia e caratteristiche vincenti - slides
LinuxDay 2004 - Linux - Storia e caratteristiche vincenti - slidesMaurizio Antonelli
 
Marco Signorelli 19 09 2008 Ordine Degli Avvocati Di Bergamo
Marco Signorelli   19 09 2008 Ordine Degli Avvocati Di BergamoMarco Signorelli   19 09 2008 Ordine Degli Avvocati Di Bergamo
Marco Signorelli 19 09 2008 Ordine Degli Avvocati Di BergamoAndrea Rossetti
 
Pf e netfilter, analisi dei firewall open source
Pf e netfilter, analisi dei firewall open sourcePf e netfilter, analisi dei firewall open source
Pf e netfilter, analisi dei firewall open sourceGiovanni Bechis
 
Introduzione Alla Uml Mconsole
Introduzione Alla Uml MconsoleIntroduzione Alla Uml Mconsole
Introduzione Alla Uml MconsoleMajong DevJfu
 
Linux Security Hardening - panoramica sui principi generali per la riduzione...
Linux  Security Hardening - panoramica sui principi generali per la riduzione...Linux  Security Hardening - panoramica sui principi generali per la riduzione...
Linux Security Hardening - panoramica sui principi generali per la riduzione...Marco Ferrigno
 
Security and hacking engineering - metodologie di attacco e difesa con strume...
Security and hacking engineering - metodologie di attacco e difesa con strume...Security and hacking engineering - metodologie di attacco e difesa con strume...
Security and hacking engineering - metodologie di attacco e difesa con strume...Marco Ferrigno
 
Cyber Forensics - Acquisizione e analisi dei dati
Cyber Forensics - Acquisizione e analisi dei datiCyber Forensics - Acquisizione e analisi dei dati
Cyber Forensics - Acquisizione e analisi dei datiMarco Ferrigno
 

La actualidad más candente (17)

Inferno Limbo Italian
Inferno Limbo ItalianInferno Limbo Italian
Inferno Limbo Italian
 
2013 pillole 02
2013 pillole 022013 pillole 02
2013 pillole 02
 
Pycrashcourse3.0
Pycrashcourse3.0Pycrashcourse3.0
Pycrashcourse3.0
 
Linux Day 2014 - Napoli - Programma Il Futuro: una scelta open source
Linux Day 2014 - Napoli - Programma Il Futuro: una scelta open sourceLinux Day 2014 - Napoli - Programma Il Futuro: una scelta open source
Linux Day 2014 - Napoli - Programma Il Futuro: una scelta open source
 
LinuxDay 2004 - Linux - Storia e caratteristiche vincenti - slides
LinuxDay 2004 - Linux - Storia e caratteristiche vincenti - slidesLinuxDay 2004 - Linux - Storia e caratteristiche vincenti - slides
LinuxDay 2004 - Linux - Storia e caratteristiche vincenti - slides
 
Marco Signorelli 19 09 2008 Ordine Degli Avvocati Di Bergamo
Marco Signorelli   19 09 2008 Ordine Degli Avvocati Di BergamoMarco Signorelli   19 09 2008 Ordine Degli Avvocati Di Bergamo
Marco Signorelli 19 09 2008 Ordine Degli Avvocati Di Bergamo
 
Packet Sniffing
Packet SniffingPacket Sniffing
Packet Sniffing
 
Pf e netfilter, analisi dei firewall open source
Pf e netfilter, analisi dei firewall open sourcePf e netfilter, analisi dei firewall open source
Pf e netfilter, analisi dei firewall open source
 
2006 Py03 intermedio
2006 Py03 intermedio2006 Py03 intermedio
2006 Py03 intermedio
 
Introduzione Alla Uml Mconsole
Introduzione Alla Uml MconsoleIntroduzione Alla Uml Mconsole
Introduzione Alla Uml Mconsole
 
Linux Security Hardening - panoramica sui principi generali per la riduzione...
Linux  Security Hardening - panoramica sui principi generali per la riduzione...Linux  Security Hardening - panoramica sui principi generali per la riduzione...
Linux Security Hardening - panoramica sui principi generali per la riduzione...
 
2006 Py04 avanzato
2006 Py04 avanzato2006 Py04 avanzato
2006 Py04 avanzato
 
Security and hacking engineering - metodologie di attacco e difesa con strume...
Security and hacking engineering - metodologie di attacco e difesa con strume...Security and hacking engineering - metodologie di attacco e difesa con strume...
Security and hacking engineering - metodologie di attacco e difesa con strume...
 
2006 Py02 base
2006 Py02 base2006 Py02 base
2006 Py02 base
 
2008 python
2008 python2008 python
2008 python
 
Funzioni hash con PHP
Funzioni hash con PHPFunzioni hash con PHP
Funzioni hash con PHP
 
Cyber Forensics - Acquisizione e analisi dei dati
Cyber Forensics - Acquisizione e analisi dei datiCyber Forensics - Acquisizione e analisi dei dati
Cyber Forensics - Acquisizione e analisi dei dati
 

Destacado (20)

knowquestion :: agile team management
knowquestion :: agile team managementknowquestion :: agile team management
knowquestion :: agile team management
 
E Businesses
E BusinessesE Businesses
E Businesses
 
Linux & Open Source - Lezione 2
Linux & Open Source - Lezione 2Linux & Open Source - Lezione 2
Linux & Open Source - Lezione 2
 
Ada it#02
Ada it#02Ada it#02
Ada it#02
 
Energiak etorkizunean maketa
Energiak etorkizunean maketaEnergiak etorkizunean maketa
Energiak etorkizunean maketa
 
Lezione Cinque
Lezione CinqueLezione Cinque
Lezione Cinque
 
Unidad i parte a[1]
Unidad i   parte a[1]Unidad i   parte a[1]
Unidad i parte a[1]
 
Lezione Quattro
Lezione QuattroLezione Quattro
Lezione Quattro
 
CEUTF - TEOLOGIA
CEUTF - TEOLOGIACEUTF - TEOLOGIA
CEUTF - TEOLOGIA
 
Formato plano 6th week4
Formato plano 6th week4Formato plano 6th week4
Formato plano 6th week4
 
Galeria Rammstein Slides
Galeria Rammstein SlidesGaleria Rammstein Slides
Galeria Rammstein Slides
 
Asterisk
AsteriskAsterisk
Asterisk
 
Fast Wsdl Tutorial
Fast Wsdl TutorialFast Wsdl Tutorial
Fast Wsdl Tutorial
 
Domingo De Ramos En La Noche
Domingo De Ramos En La NocheDomingo De Ramos En La Noche
Domingo De Ramos En La Noche
 
Time Management
Time ManagementTime Management
Time Management
 
Seo Survival Guide for Business Owners
Seo Survival Guide for Business OwnersSeo Survival Guide for Business Owners
Seo Survival Guide for Business Owners
 
Formato plano 8th week6_passive_present
Formato plano 8th week6_passive_presentFormato plano 8th week6_passive_present
Formato plano 8th week6_passive_present
 
Gettingreadyfordaycare
GettingreadyfordaycareGettingreadyfordaycare
Gettingreadyfordaycare
 
123
123123
123
 
Formato plano 7th week6_pre_perf_simpast
Formato plano 7th week6_pre_perf_simpastFormato plano 7th week6_pre_perf_simpast
Formato plano 7th week6_pre_perf_simpast
 

Similar a Multithreading, multiprocessing e Asincronia

Comunicazione tra procesi Linux
Comunicazione tra procesi LinuxComunicazione tra procesi Linux
Comunicazione tra procesi LinuxMarco Buttolo
 
Elementidi informatica
Elementidi informaticaElementidi informatica
Elementidi informaticagiu89
 
Ridirezionamento di I/O con Bash: un breve approfondimento
Ridirezionamento di I/O con Bash: un breve approfondimentoRidirezionamento di I/O con Bash: un breve approfondimento
Ridirezionamento di I/O con Bash: un breve approfondimentoBabel
 
HEALTHCARE-FISIRAD-Informatica di Base
HEALTHCARE-FISIRAD-Informatica di BaseHEALTHCARE-FISIRAD-Informatica di Base
HEALTHCARE-FISIRAD-Informatica di BaseLeonardo Pergolini
 
Programma il futuro : una scelta Open Source
Programma il futuro : una scelta Open SourceProgramma il futuro : una scelta Open Source
Programma il futuro : una scelta Open SourceNaLUG
 
Programma il futuro: una scelta open source
Programma il futuro: una scelta open sourceProgramma il futuro: una scelta open source
Programma il futuro: una scelta open sourceMarco Ferrigno
 
Power point sistemi operativi , luca marcella 3° e
Power point sistemi operativi , luca marcella 3° ePower point sistemi operativi , luca marcella 3° e
Power point sistemi operativi , luca marcella 3° eLuca Marcella
 
Presentazione Linux
Presentazione LinuxPresentazione Linux
Presentazione LinuxMatteo
 
Introduzione User Mode Linux
Introduzione User Mode LinuxIntroduzione User Mode Linux
Introduzione User Mode LinuxMajong DevJfu
 
MINI CORSO INFORMATICO exchange .pptx
MINI CORSO INFORMATICO exchange .pptxMINI CORSO INFORMATICO exchange .pptx
MINI CORSO INFORMATICO exchange .pptxssuser1cba1b
 
Thanatos - Parallel & Distributed Computing
Thanatos -  Parallel & Distributed ComputingThanatos -  Parallel & Distributed Computing
Thanatos - Parallel & Distributed ComputingIdriss Riouak
 
Hardening
HardeningHardening
HardeningNaLUG
 

Similar a Multithreading, multiprocessing e Asincronia (20)

Comunicazione tra procesi Linux
Comunicazione tra procesi LinuxComunicazione tra procesi Linux
Comunicazione tra procesi Linux
 
Elementidi informatica
Elementidi informaticaElementidi informatica
Elementidi informatica
 
Sistemi operativi
Sistemi operativiSistemi operativi
Sistemi operativi
 
Ridirezionamento di I/O con Bash: un breve approfondimento
Ridirezionamento di I/O con Bash: un breve approfondimentoRidirezionamento di I/O con Bash: un breve approfondimento
Ridirezionamento di I/O con Bash: un breve approfondimento
 
HEALTHCARE-FISIRAD-Informatica di Base
HEALTHCARE-FISIRAD-Informatica di BaseHEALTHCARE-FISIRAD-Informatica di Base
HEALTHCARE-FISIRAD-Informatica di Base
 
Sist op
Sist opSist op
Sist op
 
Sistemi Operativi
Sistemi OperativiSistemi Operativi
Sistemi Operativi
 
Socket python
Socket pythonSocket python
Socket python
 
HARDWARE & SOFTWARE
HARDWARE & SOFTWAREHARDWARE & SOFTWARE
HARDWARE & SOFTWARE
 
Programma il futuro : una scelta Open Source
Programma il futuro : una scelta Open SourceProgramma il futuro : una scelta Open Source
Programma il futuro : una scelta Open Source
 
Programma il futuro: una scelta open source
Programma il futuro: una scelta open sourceProgramma il futuro: una scelta open source
Programma il futuro: una scelta open source
 
Power point sistemi operativi , luca marcella 3° e
Power point sistemi operativi , luca marcella 3° ePower point sistemi operativi , luca marcella 3° e
Power point sistemi operativi , luca marcella 3° e
 
Presentazione Linux
Presentazione LinuxPresentazione Linux
Presentazione Linux
 
Introduzione User Mode Linux
Introduzione User Mode LinuxIntroduzione User Mode Linux
Introduzione User Mode Linux
 
MINI CORSO INFORMATICO exchange .pptx
MINI CORSO INFORMATICO exchange .pptxMINI CORSO INFORMATICO exchange .pptx
MINI CORSO INFORMATICO exchange .pptx
 
Concetti base di networking
Concetti base di networkingConcetti base di networking
Concetti base di networking
 
Thanatos - Parallel & Distributed Computing
Thanatos -  Parallel & Distributed ComputingThanatos -  Parallel & Distributed Computing
Thanatos - Parallel & Distributed Computing
 
Thanatos
ThanatosThanatos
Thanatos
 
Hardening
HardeningHardening
Hardening
 
Erlug
ErlugErlug
Erlug
 

Más de Sebastiano Merlino (eTr) (20)

How to build SOLID code
How to build SOLID codeHow to build SOLID code
How to build SOLID code
 
Biomeccatronica
BiomeccatronicaBiomeccatronica
Biomeccatronica
 
Openid+Opensocial
Openid+OpensocialOpenid+Opensocial
Openid+Opensocial
 
Bash programming
Bash programmingBash programming
Bash programming
 
Lezione Uno Pratica
Lezione Uno PraticaLezione Uno Pratica
Lezione Uno Pratica
 
Lezione Tre Pratica
Lezione Tre PraticaLezione Tre Pratica
Lezione Tre Pratica
 
Lezione tre
Lezione treLezione tre
Lezione tre
 
Lezione Due Pratica
Lezione Due PraticaLezione Due Pratica
Lezione Due Pratica
 
Lezione uno
Lezione unoLezione uno
Lezione uno
 
Lezione due
Lezione dueLezione due
Lezione due
 
Wsmo Restricted
Wsmo RestrictedWsmo Restricted
Wsmo Restricted
 
Sawsdl Restriced
Sawsdl RestricedSawsdl Restriced
Sawsdl Restriced
 
Owl Guide Resticted
Owl Guide RestictedOwl Guide Resticted
Owl Guide Resticted
 
Owl S Restricted
Owl S RestrictedOwl S Restricted
Owl S Restricted
 
Lezione Tre
Lezione TreLezione Tre
Lezione Tre
 
Linux & Open Source - Alternative Software
Linux & Open Source - Alternative SoftwareLinux & Open Source - Alternative Software
Linux & Open Source - Alternative Software
 
Linux & Open Source - Lezione 2 Supporto
Linux & Open Source - Lezione 2 SupportoLinux & Open Source - Lezione 2 Supporto
Linux & Open Source - Lezione 2 Supporto
 
Linux & Open Source - Lezione 1 Supporto
Linux & Open Source - Lezione 1 SupportoLinux & Open Source - Lezione 1 Supporto
Linux & Open Source - Lezione 1 Supporto
 
Linux & Open Source - Lezione 1
Linux & Open Source - Lezione 1Linux & Open Source - Lezione 1
Linux & Open Source - Lezione 1
 
Relazione Progetto cRIO
Relazione Progetto cRIORelazione Progetto cRIO
Relazione Progetto cRIO
 

Multithreading, multiprocessing e Asincronia

  • 1. Linux Internals: Multiprocessing, Multithreading e Asincronia Come aumentare le prestazioni parallelizzando Sebastiano Merlino merlino.sebastiano@gmail.com
  • 2. Perch´ parallellizzare? e Migliora le prestazioni del programma (mentre un processo ` in e attesa per esempio in fase di I/O, un altro pu` lavorare). o Migliora la distribuibilit` del programma (rendendolo pronto per a la scalabilit` orizzontale). a ` spesso vitale e necessario (come nel caso delle interfaccie E grafiche). ` E utile a volte persino in termini di modularit` e leggibilit` del a a codice.
  • 3. Multiprocessing Con multiprocessing, in questo contesto, intendiamo l’esecuzione di multipli processi software concorrenti che abbiano spazi di memoria indipendenti. I processi su Linux proliferano mediante meccanismo di generazione. Il processo di sistema operativo che si occupa della generazione di tutti i processi kernel necessari ` init. Ogni e processo ` identificato da un PID univoco. e Il meccanismo scelto su linux per la generazione di nuovi processi ` la cosiddetta fork utilizzando la quale un processo e sdoppia il proprio spazio di indirizzi in memoria permetterndo l’esecuzione di un nuovo processo che sfrutti questa copia.
  • 4. Fork La funzione fork (int fork()) trasforma un singolo processo in esecuzione in due processi identici, noti come parent e child. Quando l’esecuzione ha successo, la fork ritorna 0 al processo child e il PID del child al processo parent. #include <unistd.h> #include <stdio.h> int main() { int cpid = fork(); if(cpid > 0) { printf("I am the father and this is my child: %dn", cpid); } else if (cpid == 0) { printf("I am the childn"); } else { printf("Error!"); } }
  • 5. Meccanismi di IPC ` E spesso necessario rendere possibile ai processi creati il comunicare fra loro. I sistemi di IPC (Inter-process communication) che Linux fornisce sono svariati: Pipe (< stdio.h >) Signal (< signal.h >) Message Queues (< sys/msg .h >) Semaphores (< sys/sem.h >) Shared Memory (< sys/shm.h >) Socket (< sys/socket.h >)
  • 6. Pipe Le Pipe sono oggetti grazie ai quali l’output di un processo pu` o essere iniettato in input ad un altro processo. Linux fornisce due modi di definire pipe: 1. FILE* popen(char* command, char* type) - apre una pipe ove command ` il processo con il quale ci vogliamo connettere. e Il tipo pu` essere “r” in lettura o “w” in scrittura. Le pipe cos` o ı aperte vanno chiuse tramite pclose(FILE* fs) e vengono scritte/lette tramite l’utilizzo di fprintf e fscanf. 2. int pipe(int fd[2]) - crea una pipe restituendo due file descriptor. fd[0] ` aperto in lettura ed fd[1] ` aperto in e e scrittura. Le pipe vanno sempre chiuse mediante metodo close(int fd). Vengono sfruttati i metodi read e write.
  • 7. #include <signal.h> #include <stdio.h> int main() { int pdes[2]; pipe(pdes); if(fork() == 0) { char received_message[10]; close(pdes[1]); read(pdes[0], (void*) received_message, 9); printf("message received: %sn", received_message); } else { close(pdes[0]); write(pdes[1], (void*) "Hello!", 7); printf("message sent: Hello!n"); } return 0; }
  • 8. Signal I segnali sono interrupt generati via software che possono essere inviati ad un processo per segnalargli che ` avvenuto un evento. e I segnali possono essere generati in maniera sincrona, ma sono genealmente meccanismi asincroni. Essi sono identificati univocamente da un numero intero compreso tra 0 e 31. Due sono i modi pi` comuni per l’invio di un segnale: u int kill(int pid, int signal) - ` una chiamata di sistema che e permette di emettere un segnale. Se il pid ` maggiore di zero, il e processo da esso identificato sar` l’unico destinatario; nel caso a in cui il pid sia zero, il messaggio sar` inviato a tutti. a int raise(int signal) - invia un messaggio al processo running. Utilizza kill in maniera trasparente ponendo come pid quello del processo che la esegue.
  • 9. Signal Un’applicazione pu` definire una funzione cosiddetta che verr` o a invocata quando uno specifico segnale viene ricevuto. L’handler per i segnali viene definito tramite la chiamata int (*signal(int sig, void (*func)()))(); ricevuto il segnale identificato da sig, la funzione func verr` invocata. func pu` a o assumere tre valori: SIG DFL - funzione di default; il processo sar` terminato una a volta ricevuto il segnale SIG IGN - funzione ignore; il segnale verr` catturato ed ignorato a un generico puntatore a funzione.
  • 10. #include <stdio.h> #include <signal.h> void sigproc(void); void quitproc(void); main() { signal(SIGINT, sigproc); signal(SIGQUIT, quitproc); printf(‘‘ctrl-c disabled use ctrl-$backslash$$backslash$ to quit$backslash$n’’); for(;;); /* infinite loop */} void sigproc() { signal(SIGINT, sigproc); /* */ /* NOTE some versions of UNIX will reset signal to default after each call. So for portability reset signal each time */ printf(‘‘you have pressed ctrl-c $backslash$n’’); } void quitproc() { printf(‘‘ctrl-$backslash$$backslash$ pressed to quit$backslash$n’’); exit(0); /* normal exit status */ }
  • 11. Message Queues Le code di messaggi si basano su uno schema molto semplice. Un processo piazza un messaggio all’interno di una struttura (una coda) fornita dal sistema operativo. Un altro processo, conoscendo l’identificativo della coda da cui leggere potr`a successivamente recuperare il messaggio. Una coda di messaggi pu` essere inizializzata mediante il o metodo int msgget(key t key, int msgflg); il metodo ritorna l’identificativo univoco della coda - i parametri specificati rappresentano il nome assengato alla coda e dei flag utili per il management dei diritti. Un messaggio viene inserito nella coda tramite il metodo msgsnd e viene invece recuperato mediante msgrcv.
  • 12. Semaphores I semafori costituiscono un fondamentale sistema di coordinamento tra processi. Qualora due o pi` processi condividano la stessa risorsa mediante u meccanismi di IPC ` vitale che l’accesso a tale risorsa sia e correttamente gestito (osserveremo meglio questo problema nella parte dedicata ai thread). Un semaforo viene inizializzato (o se ne ottiene accesso) tramite: int semget(key t key, int nsems, int semflg); ove, key rappresenta un nome associato all’id univoco che la funzione ritorna; nsems indica il numero di semafori che si vogliono ottenere e semflg sono i flag di gestione assegnati al semaforo. Operazioni sul semaforo vengono eseguite mediante la direttiva int semop(int semid, struct sembuf *sops, size t nsops);
  • 13. Shared Memory La shared memory rappresenta il metodo, forse pi` veloce di scambiare dati fra u processi differenti. In sostanza, un processo crea un’area di memoria alla quale altri processi possono accedere (se viene loro dato diritto). Questo metodo si porta ovviamente dietro il problema della condivisione di una risorsa e pertanto porta all’insorgenza della necessit` di sincronizzare l’accesso da parte dei processi a alla memoria condivisa. Un segmento di memoria condivisa ` acceduto tramite int shmget(key t key, size t e size, int shmflg); Per potere usare la memoria condivisa, il processo deve farne attach al suo spazio di indirizzi; questo viene fatto tramite void *shmat(int shmid, const void *shmaddr, int shmflg); che ritorner` in shmaddr l’indirizzo alla head della a memoria condivisa. Il processo rilascia l’accesso tramite int shmdt(const void *shmaddr); Trascuro per ora le problematiche di sincronizzazione, essendo queste simili per molti versi a quelle successivamente trattate nella parte dedicata ai thread.
  • 14. Socket Le Socket costituiscono un sistema di IPC punto-punto e bidirezione. Pur non essendo il sistema pi` veloce di comunicazione, la loro versatilit` e la u a possibilit` di usarle attraverso la rete le rendono molto usate. a Esistono 4 tipi di socket: Stream Socket (SOCK STREAM) - bidirezionali, sequenziali, affidabili e non duplicati senza limiti di trasmissione. Usa TCP. Datagram Socket (SOCK DGRAM) - bidirezionali, non assicurano l’ordine dei messaggi che sono costituiti da pacchetti di dimensione finita. Non necessita di connessione. Usa UDP Sequential Packet Socket (SOCK SEQPACKET) - essenzialmente un Datagram ma sequenziale, affidabile e con connessione. Mai implementato. Raw - utilizza direttamente i protocolli di comunicazione.
  • 15. Socket Le Socket vengono create mediante la funzione int socket(int domain, int type, int protocol) (se il protocollo non ` specificato esso sar` il default per il tipo). Le Socket si e a collegano le une alle altre tramite indirizzi. Per assegnare un indirizzo ad una socket si usa il metodo int socket(int domain, int type, int protocol). Le connessioni tramite Socket sono solitamente non bilanciate (client-server). Il server (in una connessione STREAM) chiama int listen(int s, int backlog) ove backlog rappresenta il numero massimo di connessioni da accodare. Il client per collegarsi al Server chiamer` int connect(int s, struct sockaddr *name, int a namelen) e, infine, il server, per accettare la connessione eseguir` int connect(int s, a struct sockaddr *name, int namelen) che restituisce il file descriptor di una socket dedicata esclusivamente alla connessione. In una socket stream, la ricezione e l’invio dei messaggi sono eseguiti mediante i metodi read() e write() o, alternativamente, recv(...) e send(...). In una socket datagram, invece si usano i metodi sendto() e recvfrom() o, in alternativa, recvmsg() e sendmsg.
  • 16. Soluzioni differenti - OpenMP OpenMP ` una API che supporta il multiprocessing con memoria condivisa. e La semantica della libreria ` cos` semplice da farla apparire quasi come una funzionalit` del linguaggio. e ı a La libreria si occupa in maniera del tutto trasparente per il programmatore del partizionamento dei dati e della distribuzione tra i core del codice. #include <stdio.h> int main(void) { #pragma omp parallel printf("Hello, world.n"); // Verr` stampato una volta per ogni processore a return 0; } int main(int argc, char *argv[]) { const int N = 100000; int i, a[N]; #pragma omp parallel for // k cicli saranno eseguiti in parallelo (con k numero di processori) for (i = 0; i < N; i++) a[i] = 2 * i; return 0; }
  • 17. Multithreading Possiamo considerare un Thread come un lightweight Process. L’utilizzo di soluzioni multithread ha grandi benefici: Aumenta la responsivit` - in presenza di GUI, ad esempio, a permette di dedicare un thread ad ogni attivit` grafica. a Usa in maniera pi` efficiente i sistemi multiprocessore - ` pi` u e u facile scalare rispetto al numero di processori applicazioni multithread. Migliora la struttura di programma - molti programmi risultano meglio strutturati come sistemi a parti semi-indipendenti che come monoliti.
  • 18. Confronto tra Multiprocessing e Multithreading I benefici dei thread rispetto ai processi consistono essenzialmente in: minor tempo per essere creati (dato che sfruttano l’address space senza copiarlo) minor tempo per essere terminati minor tempo per switchare da un thread ad un altro (rispetto a quello richiesto per switchare da un processo all’altro) minore overhead dovuto alla comunicazione Il vantaggio dei processi sui thread `, invece rappresentato da un e maggior livello di isolamento.
  • 19. Pthreads La libreria pi` importante per la realizzazione di codice u multithread ` libpthread (pthread.h). e Per creare un thread si usa int pthread create(pthread t *tid, const pthread attr t *tattr, void*(*start routine)(void *), void *arg); - se non si passano attributi, il thread sar` non a detachato e erediter` la priorit` del padre. a a La libpthread ` parecchio complessa e contiene molti metodi e per la gestione e l’inizializzazione dei thread dei quali non tratteremo qui (creare variabili thread local, gestione priorit`, a ecc...).
  • 20. Sincronizzazione La libpthread offre anche vari meccanismi di sincronizzazione fra i thread. La sincronizzazione in questo caso ` vitale poich´ i thread e e condividono lo stesso spazio di indirizzi. Mutual exclusion locks (Mutex) Condition variable attributes Semaphores (non li tratteremo in quanto molto simili a quelli visti per i processi)
  • 21. Sincronizzazione Mutex I mutex rappresentano un sistema molto diffuso di serializzazione delle operazioni; essi sincronizzano i thread serializzando l’accesso a porzioni del codice definite sezioni critiche. Un mutex viene creato tramite le funzione int pthread mutex init(pthread mutex t *mp, const pthread mutexattr t *mattr); - ove il passaggio degli attributi ` del e tutto arbitrario. Esistono mutex di varia natura (unici, condivisi, scoped, ecc...) e, le varie tipologie, se non fornite in libreria, sono facilmente realizzabili. I mutex vengono lockati e slockati rispettivamente tramite le funzioni pthread mutex lock e pthread mutex unlock.
  • 22. Sincronizzazione Condition Variables Le Condition Variables sono usate per bloccare atomicamente un thread finch´ un e determinato evento non si verifica; esse sono sempre utilizzate in congiunzione con Mutex e lock. Si controlla la condizione dopo avere acquisito il lock e, nel caso questa non sia verificata ci si mette in wait sulla condizione mentre atomicamente si rilascia il lock. Quando un altro thread cambia la condizione e notifica il cambio si riacquisisce il lock e si rivaluta la condizione. Le Condition Variables sono inizializzate cos` int ı pthread cond init(pthread cond t *cv, const pthread condattr t *cattr); Varie versioni del metodo wait (semplice, temporizzata, ecc...) possono essere usate per attendere che la condizione si verifichi La condizione pu` essere segnalata mediante: int o pthread cond signal(pthread cond t *cv);. Il modo corretto di mettersi in attesa su una condition variable ` il seguente: e pthread_mutex_lock(); while(condition_is_false) // previene Spurious WakeUp pthread_cond_wait(); pthread_mutex_unlock();
  • 23. Moderne Amenit` a Negli anni, molte altre librerie che abilitano il multithreading sono nate. Fra queste ritroviamo: boost::thread - contiene tutti i maggiori paradigmi di gestione dei thread e della loro sincronizzazione Qt - dispone di versioni ad alto livello di trasparenza delle funzionalit` fin qui esposte a
  • 24. Asincronia Risulta spesso utile non assegnare specificatamente un job ad un thread ma mantenere un pool di thread detti workers ed assegnare ad uno di essi un job solo quando si verifichi uno specifico evento che lo richieda. Quest’idea ` alla base dei pattern reactor e proactor. e Un sistema di questo tipo ` detto asincrono in quanto si oppone al e classico meccanismo sincrono basato su loop e polling o wait su condition variable in cui un job ` assegnato sempre e solo ad un e thread (nel quale quindi, per ogni job viene creato un nuovo thread). Questo sistema ` vincente in quanto ottimizza le prestazioni del e programma sia in termini di cicli eseguiti che in termini di memoria occupata; tra l’altro esso rende la quantit` di risorse necessarie al a programma prevedibile in ogni momento e non strettamente dipendente dagli input.
  • 25. Asincronia Un problema molto sentito ` quello della gestione multithread di un e sistema Thread che riceve richieste da vari client. Se le richieste fossero servite sequenzialmente, non sarebbe possibile gestire richieste concorrenti. La prima soluzione che ci viene in mente ` quella di creare un thread e per ciascuna richiesta ricevuta. In questo modo sicuramente riceviamo il problema di gestione ma si presenta un nuovo problema. Se, infatti, ricevessimo nello stesso istante una gran quantit` di richieste, eg. a 10000, avremmo uno spawn istantaneo di 10000 thread che potrebbe portare al kill del nostro processo da parte del sistema operativo. La soluzione a questo problema (peraltro noto come c10k problem) si basa proprio su meccanismi asincroni come quelli descritti precedentemente; molti di questi si basano sull’utilizzo di select e poll.
  • 26. select e poll select e poll sono potenti strumenti per il multiplexing delle socket. Un programmatore pu` usare questi strumenti per scoprire quando un evento di o scrittura sia avvenuto su una socket cos` da comprendere che ` il momento ı e di leggere. La select funziona come segue: int select(int nfds, fd set *readfds, fd set *writefds, fd set *errorfds, struct timeval *timeout); ove nfds ` il fd di e valore pi` alto, readfds, writefds e errorfds sono dei set di file descriptor da u controllare e timeout ` un eventuale timeout che scatta qualora non e avvengano eventi su nessun file descriptor. La funzione torna il numero di fd su cui ` avvenuto un evento e riempie i set con solo i file descriptor su e cui sono avvenuti eventi. La poll ` un’evoluzione della select che ne migliora essenzialmente la e semantica. Essa permette di specificare il tipo di eventi su cui porsi in ascolto (oltre a supportare un numero maggiore di eventi). Ad oggi poll() ` e deprecata e sarebbe bene usare la nuova versione detta epoll().