Anteprima
Vedrai una selezione di 10 pagine su 155
Appunti Sistemi operativi - parte 6 Pag. 1 Appunti Sistemi operativi - parte 6 Pag. 2
Anteprima di 10 pagg. su 155.
Scarica il documento per vederlo tutto.
Appunti Sistemi operativi - parte 6 Pag. 6
Anteprima di 10 pagg. su 155.
Scarica il documento per vederlo tutto.
Appunti Sistemi operativi - parte 6 Pag. 11
Anteprima di 10 pagg. su 155.
Scarica il documento per vederlo tutto.
Appunti Sistemi operativi - parte 6 Pag. 16
Anteprima di 10 pagg. su 155.
Scarica il documento per vederlo tutto.
Appunti Sistemi operativi - parte 6 Pag. 21
Anteprima di 10 pagg. su 155.
Scarica il documento per vederlo tutto.
Appunti Sistemi operativi - parte 6 Pag. 26
Anteprima di 10 pagg. su 155.
Scarica il documento per vederlo tutto.
Appunti Sistemi operativi - parte 6 Pag. 31
Anteprima di 10 pagg. su 155.
Scarica il documento per vederlo tutto.
Appunti Sistemi operativi - parte 6 Pag. 36
Anteprima di 10 pagg. su 155.
Scarica il documento per vederlo tutto.
Appunti Sistemi operativi - parte 6 Pag. 41
1 su 155
D/illustrazione/soddisfatti o rimborsati
Disdici quando
vuoi
Acquista con carta
o PayPal
Scarica i documenti
tutte le volte che vuoi
Estratto del documento

Confronto tra tempi di creazione di thread e processi

Nella figura sotto possiamo osservare una tabella che mette in comparazione i tempi di creazione di un thread con i tempi di creazione di un processo. I tempi di creazione di un thread sono minori di un ordine di grandezza rispetto ai tempi di creazione di un processo. In tabella sono presenti dei processori al quanto vecchiotti. I guadagni che si ottengono con i thread non sono solo a livello prestazionale ma si hanno anche guadagni a livello di comunicazione. Per la comunicazione tra i processi bisogna inventarsi tutta una serie di meccanismi di comunicazione interprocesso, questi meccanismi IPC che sono shared memory, semafori e code di messaggi perché dopo la fork, dopo che ogni processo viene ad essere creato otteniamo la copia esatta del padre e quindi non abbiamo nessuna area condivisa tra i processi se non queste aree apposite create con funzionalità apposite del Kernel. Usando i thread la condivisione di dati è molto più efficiente e facile in quanto i thread.

hanno lo stesso spazio di indirizzamento mentre i processi no

I thread condividono lo stesso spazio di indirizzamento, mentre i processi hanno spazi di indirizzamento separati.

L'area heap viene condivisa tra i thread

L'area heap è condivisa tra i thread, mentre ogni thread ha le sue aree dati stack e codice specifiche.

Ogni thread ha il suo stack

Ogni thread ha il suo stack. Quando viene creato un thread utilizzando la funzione Pthread Create in Linux, vengono gestite le aree comuni e non comuni.

L'area dati globale è comune a tutti i thread figli di un thread padre

L'area dati globale è comune a tutti i thread figli di un thread padre.

facciamo applicazioni multiprocesso, quando si va ad implementare il main qui non viene ad essere automaticamente creato un processo all'atto dell'esecuzione del programma eseguibile ma viene ad essere creato un thread che prende il nome di thread master. In realtà in Linux/UNIX abbiamo che l'unità fondamentale è un task che altro non è che un thread, quindi abbiamo che è più facile la comunicazione in quanto non bisogna andare a gestire la creazione della shared memory, l'attach e tutte quelle cose che abbiamo visto essere dispendiose da utilizzare. In questo caso siccome le aree di memoria sono condivise, l'area heap e l'area dati globale, la libreria pthread fornisce dei meccanismi per la sincronizzazione che sono importanti per andare a disciplinare e per gestire una cooperazione o una competizione tra i thread che sono meccanismi necessari come quelli ad esempio usati per i processi. Si avranno quindi una sorta

disemafori che non sono semafori ma delle funzioni come quelle per la gestione dei thread, per la gestione dei mutex e per la gestione delle variabili condition. Implicitamente usando la libreria pthread sarà possibile andare ad utilizzare un mutex per gestire la sincronizzazione ma generalmente stiamo usando un monitor per gestire la cooperazione e la competizione tra i thread di uno stesso processo. Quando dobbiamo andare a gestire o implementare un'applicazione multi thread e dobbiamo andare a gestire un problema produttore consumatore questo lo andremo ad implementare come se fosse un problema produttore consumatore con monitor signal and continue e quindi il processo che segnala continuerà la sua esecuzione all'interno del monitor. N.B Oggi la libreria pthread e tutte le funzioni sono create all'interno di un branch della libreria C (Gnu LibC), se vogliamo possiamo andare ad osservare tutte le librerie disponibili alPuoi trovare il codice sorgente pthread su questo repository: [link](sitocode.woboq.org/userspace/glibc/npti/). La prima funzione che utilizzeremo per i pthread è `pthread_create`, che è l'equivalente di `fork`. Questa funzione richiede 4 parametri: - L'identificatore del thread creato di tipo `pthread_t`. - Gli attributi utilizzati per la creazione di questi thread, che permettono di impostare se i thread possono essere joinabili o meno (equivalente di `wait` per i processi). - Il parametro `start_routine`, che è un puntatore a `void` e rappresenta la funzione che deve essere invocata al momento della creazione. - Gli argomenti che vengono passati alla funzione. Possiamo notare che ci sono dei vincoli specificati nella firma di questa funzione.dobbiamo stare attenti agli ultimi due argomenti. Per quanto riguarda lo start_routine dobbiamo dare attenzione che sia di tipo void * e quindi questo ci obbliga ad utilizzare il valore di ritorno per la funzione che si va ad invocare che è del tipo void*. Per passare dei parametri di tipo intero, di tipo struttura dobbiamo andare a fare il type casting inverso, andiamo quindi a passare un void * e poi andremo a fare un type casting all'interno della funzione. La funzione di terminazione abbiamo che rappresenta l'analogo della funzione exit per un processo. Generalmente il thread abbiamo che può terminare naturalmente, quando invochiamo la pthread_exit() esplicitamente, può essere cancellato da un altro thread che può far terminare prematuramente un altro thread tramite l'utilizzo della pthread_cancel() oppure termina quando termina il processo. La pthread_exit oltre ad essere usata per far terminare esplicitamente un thread viene ad essere

usata anche nel main alla fine e quindi quando terminiamo lo sviluppo dell'applicazione e questo lo si fa per evitare che altri thread continuino ad eseguire. Se si va a leggere il manuale viene ad essere riportato che è buona norma andare ad utilizzare la pthread_exit in tutti i thread e poi una pthread_exit(NULL) alla fine del main.

Nel caso in cui volessimo andare a passare più parametri alla start_routine dobbiamo andare ad usare una struttura dati che contiene al suo interno gli N parametri, questa struttura dovrà essere contenuta nell'area heap e poi potrà essere passata attraverso un type casting a void. Quando andiamo a creare il thread gli passiamo la start function che ha un valore di ritorno di tipo void *, il parametro è sempre un solo parametro di tipo void *, questa non sarà una variabile semplice ma una variabile strutturata. Quando stiamo all'interno della struct function possiamo fare il type casting al tipo di dato.

Quello presentato sopra è il modo corretto di andare ad utilizzare più parametri all'interno di una funzione di un thread. Quando ad esempio affrontiamo un problema produttore consumatore andremo ad utilizzare una struttura dati in quanto ci serviranno più variabili per il buffer, per variabili di stato che servono a disciplinare l'accesso ecc. Facciamo praticamente un esempio ed andiamo ad aprire la shell. Vogliamo creare un'applicazione che fa un Hello World del thread, vogliamo quindi fare un thread che stampi a video una stringa. La prima cosa che dobbiamo andare a fare è includere la libreria pthread e poi andiamo ad includerci le solite librerie ed andiamo a crearci il main. Ci creiamo allora una variabile che mantiene i riferimenti ai vari thread, questa variabile deve avere il tipo pthread_t e questa sarà la variabile che andremo a passare come primo argomento della pthread_create. In questo caso ci creiamo un pool di thread diNUM_THREADS, facciamo poi un ciclo che ci crei questi thread e facciamo in modo che questi thread stampino a video il loro identificativo. Facciamo poi una pthread_create ed usiamo il valore di ritorno per questa funzione che se è 0 indica che va tutto bene mentre se è diverso indica che c'è qualche problema. Possiamo andare a vedere la firma della pthread_create usando il manuale man. Possiamo osservare come questa funzione vada cercando un riferimento al thread e in questo caso è uno array di thread, possiamo osservare poi che abbiamo due void * per la start routine e per la parte di argomenti che devono essere passati alla start routine. Nel nostro esempio abbiamo quindi bisogno del riferimento e due attributi che possiamo mettere a NULL, abbiamo poi che dobbiamo andare a passargli una funzione che è a start_routine che abbiamo detto il suo valore di ritorno è void *, in questo caso dobbiamo semplicemente passare il nome della funzione chenonabbiamo ancora creato e dobbiamo poi passare il valore del parametro i che in questo caso dobbiamoandare a typecastere al void*.N.B La funzione print_hello non può essere una funzione del tipo perché il valore di ritorno deve essere obbligatoriamente void* ed è obbligatorio anche avere un unico parametro di ingresso alla funzione che è void *. Nel caso vogliamo passare più parametri andremo a passare sempre un riferimento ma un riferimento ad una struttura. Questa è una delle prime differenze rispetto ad utilizzare un'applicazione multiprocesso dove abbiamo una funzione classica mentre nel caso in esame la firma è obbligata ad essere come sopra.Quando realizziamo la funzione print_hello dobbiamo andare a mettere al suo interno una pthread_exit in quanto questa deve terminare. Nella pthread_exit possiamo andare a mettere come valore di uscita 0 o qualsiasi altro valore vogliamo in uscita. 746Quello che otteniamo con questo codice

è semplicemente che ogni volta che questo thread verrà ad esserechiamato andrà a stampare un hello per ogni thread creato fino ad un valore massimo di thread creati.

Se andassimo a compilare il programma sopra senza linkare la libreria thread otterremo quanto sotto.

Possiamo osservare che ci vengono ad essere dati solo dei warning e ci viene ad essere creato lo stessol’eseguibile ma se proviamo a mandare in esecuzione abbiamo che in automatico viene ad essere fattal’azione di linkaggio della quale ci eravamo dimenticati e questo è un side effect di MAC OS che ha capito inautomatico che stiamo usando la libreria pthread; se stiamo usando Linux dobbiamo invece ricordarci diandare a linkare la libreria pthread e quindi di andare ad usare il flag -l pthread.

Possiamo osservare poi che sopra si hanno dei warning particolari in quanto l’implementazione della libreria pthread è leggermentediversa da quella implementata in Linux.

747

allora che la riga di compilazione usata sopra non andrà bene a meno che non si è su un ambiente MAC; la riga di compilazione che dovrà essere usata sarà con il flag -lpthread quello che si va a dire al compilatore è che si intende usare ne
Dettagli
Publisher
A.A. 2022-2023
155 pagine
SSD Ingegneria industriale e dell'informazione ING-INF/05 Sistemi di elaborazione delle informazioni

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher Dadox94 di informazioni apprese con la frequenza delle lezioni di Sistemi operativi e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università degli studi di Napoli Federico II o del prof Cotroneo Domenico.