Modello Thread - Polinformatici

Transcript

Modello Thread - Polinformatici
Modello Thread Sistemi Operativi Mattia Natali Modello Thread  Concetto di thread:  Attività parallela che consente “strutturalmente” un grado di cooperazione elevato.  Sono delle attività parallele che si formano in un medesimo processo, sono pensati per attività parallele che debbano interagire, comunicare tra di loro. Mentre i processi sono nati per avere un elevato grado di indipendenza.  Si può definire come “processo leggero”, una sua versione semplificata e si rende più efficiente la gestione e la comunicazione tra vari thread.  I processi limitano il grado di comunicazione ad un intero di 256bit in uscita.  I thread sono dei flussi di attività svolti in parallelo, sono delle funzioni (sottoprogrammi).  Essi condividono lo stesso ambiente del processo, condividono le variabili globali e statiche (il modello a processi no: le varie modifiche alle variabili non influenzano i vari processi). Il problema sta nel parallelismo dei vari thread.  Programmazione concorrente: evoluzione della programmazione sequenziale, cooperazione dei vari threads.  I thread, a differenza dei processi, sono tutti sullo stesso piano.  Tutti i thread di un processo condividono la stessa memoria dati, anche se ogni processo ha pila propria per le variabili locali.  Thread POSIX:  È uno dei tanti standard dei thread che variano in base ai sistemi operativi.  Le librerie di funzioni che creano i vari thread tenendo lo standard POSIX si chiama pthread.  Noi creeremo i vari thread all’interno di un solo processo:  Il processo può attivare vari threads.  Quando il processo termina, tutti i thread vengono chiusi forzatamente.  Ogni thread ha il suo identificatore di thread, di tipo pthread_t:  Gli identificatori sono univoci e sono diversi dai pid_t.  Ogni thread può essere posto in attesa di un evento.  Il thread termina quando esegue la return() o alla fine del codice eseguibile della funzione, esso può restituire un codice di terminazione al thread che lo ha creato.  Il main è il thread principale o di default.  Terminologia:  Esecuzione sequenziale: date due “attività” A e B nel codice di un programma, esse sono sequenziali se, esaminando il codice del programma stesso, è possibile prevedere se A verrà svolta sempre prima di B oppure se B verrà svolta sempre prima di A.  Esecuzione concorrente: date due “attività” A e B nel codice di un programma, esse sono concorrenti se, esaminando il codice del programma stesso, NON è possibile prevedere se A verrà svolta sempre prima di B oppure se B verrà svolta sempre prima di A.  Esecuzione parallela: si usa questo termine come sinonimo di concorrente, perché ci si riferisce a macchine con processore singolo. Per noi parallelo e concorrente saranno sinonimi perché eseguiremo i thread su un singolo processore. 1 Modello Thread Sistemi Operativi Mattia Natali  Funzioni thread POSIX:  Creazione del thread pthread_create():  pthread_create() è simile a fork().  Il thread viene creato passandogli il nome della funzione che esso deve eseguire ed esso parte sempre dall’inizio della funzione passata.  Prototipo: pthread_create (&tID1, NULL, &tf1, (void *) 1)  Gli argomenti sono 4: • Indirizzo della variabile che conterrà l’identificatore del thread di tipo pthread_t. • Puntatore agli attributi del thread: NULL significa standard. • Passaggio dell’indirizzo di una funzione che si desidera eseguire. • Ultimo è un argomento di tipo void * che viene passato alla funzione.  Attesa di terminazione tra thread pthread_join():  pthread_join() è simile a waitpid().  Prototipo: pthread_join (tID1, (void *) &thread_exit)  Argomenti: • Variabile di tipo pthread_t che contiene l’identificatore del thread da attendere. • Valore di uscita del thread.  Si deve sempre specificare il thread di cui si vuole attendere la terminazione.  Bisogna usarlo per garantire la terminazione dei thread creati.  Differenza processi e thread:  Efficienza: i processi sono più onerosi rispetto ai thread, perché deve creare tutte le proprie strutture dati per essere eseguito. I thread sono migliori in termini di efficienza.  Protezione: se un thread va in errore causa la chiusura forzata dell’intero processo, mentre i processi non si influenzano tra loro.  Cambiamento eseguibile: può essere effettuata solamente dai processi. I thread possono ricevere solamente una funzione dell’eseguibile stesso, non può cambiare codice.  Condivisione dati: le variabili globali dei thread sono comuni, la condivisione tra processi è più complicato.  Test programma concorrente:  Simulazioni: ci mostra alcuni comportamenti ma non tutti. Ciò è molto più utile nell’esecuzione sequenziale perché sappiamo l’ordine di esecuzione.  Tecniche formali a base matematica o tecniche di logica anche se è molto complesso.  Tecniche di programmazione: 
Sequenze critiche: •
•
•
È una successione di istruzioni eseguite da più thread in parallelo che non devono essere mescolate tra loro affinchè il sirultato sia sempre corretto. Successione sequenziale di operazioni/istruzioni eseguite dal thread usando la nomenclatura ti.j = istruzione j eseguita dal thread i. Così sappiamo per certo che le istruzioni j del thread i sono eseguite sequenzialmente. Per avere le sequenze critiche bisogna assicurarsi che i thread avvengano in sequenza: se un qualsiasi thread comincia l’esecuzione della sequenza tutta la sequenza deve essere 2 Modello Thread 
Sistemi Operativi Mattia Natali eseguita da quel thread  si riduce la concorrenza. È di mutua esclusione, nessun’altra sequenza critica avviene insieme ad un’altra. Istruzioni atomiche: se si riesce a garantire che l’esecuzione dell’istruzione non possa essere interrotta (indivisibile). •


I singoli statement NON sono atomici, perché quando vengono trascritti in linguaggio macchina un singolo statement può essere suddiviso. Deallock o stallo. Sincronizzazione.  Tecniche programmazione:  Mutua esclusione (Mutex):  Costrutti specializzati della libreria pthread, il costrutto si chiama mutex che garantisce la sequenzializzazione della sequenza critica.  Quando un thread attiva un blocco, eventuali altri thread che tentano di accedere al blocco vengono messi in attesa finché il primo non libera o rilascia il blocco.  La primitiva lock è una primitiva bloccante.  Passaggi: • Dichiariamo variabile pthread_mutex_t. •
•
Inizializziamo tramite la funzione pthread_mutex_init. Blocchiamo e sblocchiamo la sequenza critica con pthread_mutex_lock e pthread_mutex_unlock. 3