Sistemi operativi
I Thread
Esempio: come è fatto un word processor
Molte azioni contemporanee e indipendenti (input, tabulazione, correzione ortografica, memorizzazione, … ) sullo stesso insieme di dati!!
Schema esplicativo (word processor)
Soluzioni
1: Più processi che comunicano attraverso una memoria condivisa
- overhead per la creazione di numerosi processi
- overhead per la gestione della memoria comune
2: Un solo processo con “stringhe di esecuzioni” indipendenti che operano sullo stesso spazio di indirizzamento
-> Stringhe di esecuzione = threads
Definizione di Threads
Nei moderni S.O. un thread (o lightweight process, LWP) è spesso l’unità di base di utilizzo della CPU e consiste di:
- Program counter
- Insieme dei registri
- Spazio dello stack
Un thread condivide con i thread ad esso associati:
- Spazio di indirizzamento (non c’è protezione !!)
- Dati globali
- File aperti
- Gestori dei segnali
Definizione di Threads
- L’insieme dei thread e dell’ambiente da essi condiviso è chiamato task.
- Un processo tradizionale, o heavyweight process, corrisponde ad un task con un solo thread.
Processi a thread singolo e multithread
In figura sono mostrati due schemi relativi a processi a thread singolo (a sinistra) e multiplo (a destra).
Processi single/multi threaded
Vantaggi dei threads
In un task multithread, mentre un thread è bloccato in attesa, un secondo thread nello stesso task può essere in esecuzione.
- La cooperazione di più thread nello stesso job fornisce un maggior throughput.
- Applicazioni che richiedono la condivisione di un buffer (es. produttore–consumatore) traggono beneficio dall’impiego di thread.
Vantaggi dei threads
- Possono essere gestiti dal sistema operativo o da una applicazione utente
- E’ un modo per condividere risorse
- Realizzano una forma di parallelismo
- Hanno un overhead molto inferiore a quelli dei processi
Ciclo di vita di un thread
Analogamente ad un processo i threads sono schedulati da uno scheduler e attraversano varie fasi:
- nuovo
- pronto
- esecuzione
- terminato
- bloccato
- in attesa
- dormiente
… ma come sempre dipende dall’implementazione
Esempio
In figura è mostrato uno schema relativo al ciclo di vita dei threads.
Modelli di implementazioni
Quasi tutti i sistemi operativi implementano i threads in uno dei seguenti modi:
- User-level threads (modello “molti a uno”)
- Kernel-level threads (modello “uno a uno”)
- Combinazione ibrida delle due modalita’ precedenti (modello “molti a molti”)
User-level Threads
I threads sono gestiti nello spazio utenti da specifiche librerie e non possono accedere direttamente alle primitive del kernel.
Gestione dei thread (user-level)
Implementazione del modello ULT
Il kernel mantiene la propria process table e i relativi PCB.
Ogni processo ha una propria thread table con relative strutture dati per la descrizione dei thread analoga (ma di dimensioni ridotte) ai PCB.
Thread a livello utente (ULT)
Vantaggi:
- Il cambio di contesto fra thread non richiede privilegi in modalità kernel (risparmia il sovraccarico del doppio cambiamento di modalità).
- Lo scheduling può essere diverso per applicazioni diverse.
- Gli ULT (User Level Thread ) possono essere eseguiti su qualunque SO senza cambiare il kernel sottostante. La libreria dei thread è un insieme di utilità a livello di applicazione.
Thread a livello utente (ULT)
Svantaggi:
- In caso di system call bloccanti, quando un thread esegue una chiamata di sistema, viene bloccato tutto il processo.
- Un’applicazione multithread non può sfruttare il multiprocessing: in un dato istante un solo thread per processo è in esecuzione.
Kernel-level Threads
I threads sono gestiti direttamente dal kernel. In questo caso i thread rappresentano l’ “unità di esecuzione” della CPU.
Gestione dei thread (kernel-level)
Implementazione del modello KLT
Il kernel mantiene:
- la process table
- i relativi PCB
- una thread table
- le relative strutture dati
Thread a livello kernel (KLT)
Vantaggi:
- Può schedulare simultaneamente più thread (predisposizione al parallelismo su multiprocessori)
- Miglioramento della scalabilità e dell’interattività
- Se un thread di un processo è bloccato il kernel può schedulare un altro thread dello stesso processo
Thread a livello kernel (KLT)
Svantaggi:
- Il trasferimento del controllo fra thread dello stesso processo richiede il passaggio in modalità kernel: l’aumento di prestazioni è meno rilevante rispetto all’approccio ULT.
- Sovraccarico del kernel che potrebbe gestire migliaia di threads (e delle relative strutture dati).
Combinazione ibrida
Ad ogni thread del kernel corrispondono più thread utente. Cerca di combinare i vantaggi dei due precedenti approcci.
Gestione dei thread (modello ibrido)
Combinazione ibrida
Realizzazione:
- Un insieme di thread permanenti (worker threads) vengono creati dal kernel e formano il “threads pool”
- Ogni nuovo thread utente è eseguito da un worker thread
Ottimizzazione
- Possibilità di specificare il numero dei worker threads in base al carico del sistema
- Schedulazione dei thread direttamente nel kernel
Esempio 1: Threads POSIX (Pthreads)
- Uno standard POSIX (IEEE 1003.1c) per la creazione e sincronizzazione dei threads
- Definizione delle API. Spesso implementati mediante libreria da usare in s.o. non dotati di thread (es. Unix)
- Threads conformi allo standard POSIX sono chiamati Pthreads
Esempio 1: Threads POSIX (Pthreads)
- Lo standard POSIX stabilisce che registri dei processori, stack e signal mask sono individuali per ogni thread
- Lo standard specifica come il sistema operativo dovrebbe gestire i segnali ai Pthtrads i specifica differenti metodi di cancellazione
- Permette di definire politiche discheduling e priorità
- Alla base di numerose librerie di supporto per vari sistemi non dotati di threads (es. Unix)
Esempio 2: Threads Linux
- Linux utilizza lo stesso tipo di struttura dati per descrivere processi e threads (Process Control Block)
- Linux chiama entrambi tasks.
- Modello KLT (uno a uno)
Per la creazione dei threads, Linux fornisce la chiamata di sistema clone( ).
- Clone accetta argomenti per specificare quali risorse devono essere condivise con il task figlio
Esempio 2: Threads Linux
In figura si mostra uno schema esplicativo della gestione dei threads in Linux.
Esempio 2: Threads Linux
La fork viene realizzata mediante la clone e la duplicazione dello spazio di indirizzamento avviene con il meccanismo di copy-on-write: le pagine vengono copiate solo quando il figlio tenta una scrittura
Schema esplicativo (clone/copy)
Esempio 3: Threads Solaris 2
- Implementazione ibrida (molti a molti)
- Tra i threads del kernel e quelli utente c’è un livello intermedio: i “processi leggeri”
- Ad ogni thread del nucleo è associato un proc leggero
- Ogni proc leggero può gestire piu’ thread utente
- Un processo tradizionale è composto da piu’ proc leggeri
Esempio 3: Threads Solaris 2
In figura si mostra uno schema esplicativo della gestione dei threads in Solaris 2.
Schema dei processi (Solaris 2)
Esempio 3: Threads Solaris 2
- Lo scheduler agisce direttamente sui threads del nucleo
- Il numero di processi leggeri varia dinamicamente in maniera da non avere mai processi bloccati
- Al termine del processo i proc leggeri non vengono immediatamente cancellati ma si cerca di “riciclarli” per altri processi
Prossima lezione
Lo scheduling dei processi
- Concetti fondamentali
- Il ruolo delle priorità
- Valutazione degli algoritmi