Nel secondo quadrimestre il progetto proposto dall'insegnante di TPSIT consisteva nel programmare un server web in C++ in ambiente Linux. Il progetto ci è stato proposto per permetterci di imparare la programmazione concorrente non studiandola sul libro ma programmando, permettendoci di capirne a fondo il funzionamento.
Abbiamo creato tre varianti dello stesso programma: una "classica" utilizzando il multiprocessing, una utilizzando l'OOP (Object Oriented Programming) e infine un'altra che utilizza i thread concorrenti.
DEFINIZIONI
Un server web è un'applicazione che si occupa della gestione dei trasferimenti di pagine web effettuati tra il server che contiene le pagine web e il client che le richiede, nel nostro caso è stato creato utilizzando un modello concorrente.
Per concorrenza si intende che la CPU esegue parti di codice contemporaneamente alle parti non concorrenti, a differenza del modello di programmazione "standard" dove tutte le istruzioni vengono eseguite sequenzialmente.
FUNZIONAMENTO DI BASE
Il funzionamento è quasi lo stesso nelle varianti classica e a oggetti, mentre in quella con i thread ci sono delle differenze dal punto di vista della programmazione.
Nel nostro caso, per non complicare il progetto relativamente alla comunicazione tra i computer, abbiamo eseguito un server web hostato localmente.
Inizialmente si immagazzinano l'URL della pagina web da trasferire e la porta che identifica il servizio da utilizzare.
- Si "accende" il server controllando che non ci siano errori durante la fase di inizializzazione
- Se è possibile accettare delle nuove connessioni il server crea un processo figlio in concorrenza relativo al client che si è appena connesso, altrimenti rifiuta la connessione
- Il processo figlio si occuperà poi di trasferire la pagina web al client che l'ha richiesta, terminando successivamente. Se non si richiede nessuna pagina web in particolare tra quelle presenti sul server se ne trasferirà una di default
- Quando termina la connessione si libera lo slot precedentemente occupato dal client, facendo così spazio per una nuova connessione
DIFFERENZE
Le differenze tra la versione a oggetti e quella a thread vanno ricercate nel loro funzionamento, infatti i processi concorrenti non pemettono di condividere la memoria tra di loro e quindi era impossibile notificare il padre della fine di una connessione avvenuta in un processo figlio. Per ovviare a questo problema abbiamo dovuto usare la libreria signal.
Un segnale è un'entità utilizzata per notificare il programma di un evento avvenuto in precedenza e, in questo caso la funzione di gestione del segnale veniva richiamata quando un figlio terminava il trasferimento e di conseguenza andava eliminato lo slot da lui occupato: la funzione rimaneva in attesa della terminazione di un figlio e, grazie all'attivazione del segnale fatta all'inizio del programma, lo eliminava.
I thread, invece, permettono di condividere la memoria in concorrenza quindi non è necessario utilizzare i segnali come nella versione con i processi, dato che i thread possono accedere tutti alla stessa area di memoria e quindi uno può notificare gli altri della fine di una connessione.
Potete trovare i codici che sono stati descritti in questo articolo qui.
Simone D'Angelo