Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
vuoi
o PayPal
tutte le volte che vuoi
MARKER
Il comando legge l'input fino a trovare la stringa MARKER.
MARKER è una stringa arbitraria (spesso si usa EOF, ma può essere qualsiasi parola).
Standard output
Redirezione dello standard output su un file: 78
comando > file
comando 1> file
→
Default: 1> >
Se il file esiste viene cancellato. Il descrittore 1 (stdout) è quello di default quindi normalmente viene omesso.
Accodamento dello standard output su un file:
comando >> file
comando 1>> file
Se il file esiste non viene cancellato.
Standard error
Redirezione (ovvero accodamento) dello standard error sul file. Analogo allo stdout ma su stderr.
Comando 2> file
Comando 2>> file
Redirezione multipla
Combinando le varie opzioni è possibile effettuare redirezioni multiple, ovvero redirezione contemporanea
dello standard output e dello standard error.
→ Sullo stesso file
Comando &> file Redirige sia l'output standard (stdout) che l'output di errore (stderr) nello
stesso file. Se il file esiste, verrà sovrascritto.
Comando &>> file Accoda sia l'output standard che l'errore standard nello stesso file. Se il
file esiste, non verrà sovrascritto.
→ Su file diversi
Comando 1> fileOut 2> fileErr Redirige l'output standard (stdout) nel file fileOut e
l'errore standard (stderr) nel file fileErr.
Comando > fileOut 2> fileErr Anche questa è una forma equivalente al caso
precedente, dove si omette 1> per l'output standard (è il default).
79
5. Threads
I thread
Limiti dei processi
I thread nascono per lo stesso motivo per cui sono nati i processi: era utile avere in parallelo l’esecuzione di
più tipi di codice, ma anche per altri problemi. Il primo è relativo ai costi di creazione di un processo che sono
relativamente elevati ed il secondo è per avere memoria condivisa (i processi non condividono quasi nulla).
Un processo può eseguire altri processi attraverso: la clonazione (fork), sostituzione del processo attuale con
un altro programma (exec) oppure chiamata esplicita (windows CreateProcess). Ogni processo ha un proprio
spazio di indirizzamento ed ha una singola traccia di esecuzione (un unico program counter). La clonazione
implica inoltre un aumento sensibile della memoria utilizzata, tempi di creazione elevati, sincronizzazione e
trasferimento di dati (costi nulli o minimi per processi indipendenti o quasi ed elevati per processi cooperanti)
poiché non condividono informazioni. Infine, la gestione dei processi multipli richiede uno scheduling
complesso e delle operazioni di context- switching costose (con intervento del kernel).
→ I processi standard sono detti processi pesanti (heavyweight processes) a causa del costo richiesto al
sistema operativo.
Dai processi ai thread
Esistono, però, casi in cui sarebbe utile avere costi minori di creazione, gestione, etc., un unico spazio di
indirizzamento e tracce multiple di controllo/esecuzione (concorrenti) all’interno di tale spazio di
indirizzamento; per questo motivo, lo standard IEEE/ANSI POSIX nel 1996 introduce il concetto di thread: un
thread è una sezione di un processo che viene schedulata ed eseguita indipendentemente dal processo
(thread) che l’ha generata. Un thread può condividere il proprio spazio di indirizzamento con altri thread.
→ Processo: unità che raggruppa risorse.
→ Thread: unità di schedulazione della CPU (processo leggero, lightweight process).
I thread di uno stesso processo condividono la sezione
di codice, la sezione di dati (variabili, descrittori di file,
etc.) e le risorse del sistema operativo (segnali, dati
condivisi come variabili statiche, esterne, dinamiche,
tra cui l’heap).
I dati che rimangono privati per il singolo thread sono
invece: il program counter e i registri hardware (visto
che più thread eseguiranno linee diverse di codice), lo
stack, ovvero, variabili locali e storia dell’esecuzione
(visto che un thread implica un flusso di esecuzione a
sé stante all’interno del processo stesso).
L’utilizzo dei thread consente tempi di risposta ridotti e risorse condivise. Creare un thread è 10-100 volte
più veloce rispetto a generare un processo e nei thread la condivisione delle risorse è automatica (rispetto ai
processi in cui non lo è). I processi possono condividere dati solo con tecniche particolari.
Si hanno anche costi minori per la gestione delle risorse visto che un’unica sezione di codice e/o dati può
servire più clienti e assegnare la memoria a un processo è costoso, ed una maggiore scalabilità poiché i
vantaggi della programmazione multi-thread aumentano nei sistemi multiprocessore. Nei sistemi multicore
80
(diverse unità di calcolo per processore) i thread permettono più semplicemente paradigmi di
programmazione concorrente basati su:
- Separazione dei compiti (Multiple Instruction SD/MD);
- Suddivisione dei dati (SI/MI Multiple Data).
Tuttavia, non esiste protezione tra thread perché tutti sono eseguiti nello stesso spazio degli indirizzi e la
protezione da parte del SO è impossibile oppure non necessaria. Se i thread non sono sincronizzati l’accesso
a dati comuni non è thread safe.
Tra i thread non esiste relazione gerarchica padre-figlia. Al thread creante viene normalmente restituito
l’identificatore del thread creato ma questo non implica una relazione gerarchica. Tutti i thread sono uguali.
Modelli di programmazione multi-thread
Esistono tre modelli di programmazione multithread:
→
- Kernel-level thread Implementazione dei thread a livello kernel;
→
- User-level thread Implementazione dei thread a livello utente (nello spazio utente);
→
- Soluzione mista o ibrida Implementazione dei thread a livello sia kernel sia user
La scelta è moderatamente controversa.
Kernel-level thread
I thread sono gestiti dal kernel. Il sistema operativo manipola (gestisce
automaticamente) tanto processi quanto thread, è a conoscenza dell’esistenza
dei thread e fornisce un supporto adeguato alla loro manipolazione. Tutte le
operazioni sui thread (creazione, sincronizzazione, etc.) sono effettuate
mediante system call.
Il sistema operativo mantiene per ciascun thread informazioni simili a quelle che
mantiene per ogni processo: tabella dei thread e Thread Control Block (TCB) per
ogni thread attivo; le informazioni gestite sono “globali” all’interno dell’intero
sistema operativo. VANTAGGI SVANTAGGI
Dato che il sistema operativo è a conoscenza dei thread può A causa del passaggio al modo kernel la
decidere: gestione è relativamente lenta e
o →
quale thread di quale processo schedulare inefficiente perché il context switch è
visione globale di tutti i thread di tutti i processi; costoso e i tempi di manipolazione sono
o →
come suddividere il tempo tra i vari processi centinaia di volte più lenti del
→
eventualmente allocare più tempo di CPU a necessario. già affermato per i
processi con molti thread rispetto a processi con processi (motivazione per la nascita dei
pochi thread. thread).
Efficace nelle applicazioni che si bloccano spesso (e.g., read C’è una limitazione nel numero massimo
bloccante): i thread ready possono essere schedulati anche se di thread (anche in base ai core
appartengono allo stesso task di un thread che ha chiamato una disponibili), perciò il sistema operativo
system call bloccante; ovvero se un thread si blocca è sempre deve controllare il numero di thread
possibile eseguirne un altro nello stesso processo o in un altro generati.
processo perchè il sistema operativo controlla tutti i thread di
tutti i processi.
Permette un effettivo parallelismo, sia all’interno dello stesso Il sistema operativo deve mantenere
→
processo, sia tra processi diversi in un sistema informazioni costose, ossia tabella dei
multiprocessore si possono eseguire thread multipli. thread e TCB
81
User-level thread
Il pacchetto dei thread è inserito completamente nello spazio dell’utente. Il
kernel non è a conoscenza dei thread e gestisce solo processi. I thread sono
gestiti run-time tramite una libreria, il che permette il supporto mediante un
insieme di chiamate a funzioni, a livello utente. Creare un thread,
sincronizzare thread, schedularli, etc., non richiede l’intervento del kernel,
poiché si utilizzano funzioni non system call
Ogni processo ha bisogno di una tabella personale dei thread in esecuzione. Le informazioni necessarie sono
minori che nel caso di gestione kernel-level: TCB di dimensioni ridotte e visibilità locale delle informazioni
all’interno del processo cioè visibilità limitata.
VANTAGGI SVANTAGGI
Non richiedono modifiche al sistema Il sistema operativo non sa dell’esistenza dei thread.
operativo.
SI possono implementare in tutti i kernel Possono essere fatte scelte inopportune oppure poco
anche nei sistemi che non supportano efficienti, per esempio il sistema operativo potrebbe
thread in maniera nativa. schedulare un processo il cui thread in esecuzione potrebbe
fare una operazione bloccante e in questo caso l’intero
processo potrebbe rimanere bloccato anche se al suo
interno diversi altri thread potrebbero essere eseguiti.
La gestione è efficiente: context switch + Anche se la gestione è a livello utente occorre comunicare le
veloce perché avviene in user-space senza informazioni tra il kernel e i manager dell’utente run-time.
coinvolgere il thread. Senza questo meccanismo di comunicazione esisterebbe solo
Manipolazione dei dati efficiente→ un thread in run per task anche in un sistema
centinaia di volte più veloci dei thread multiprocessore; non esisterebbe scheduling all’interno di un
kernel. processo singolo, ovvero non esistono interrupt all’interno di
un singolo processo. Se un thread in esecuzione non rilascia
la CPU, non sarebbe bloccabile
Al programmatore è consentito generare Lo scheduler deve mappare i thread utente sull’unico thread
tutti i thread desiderati; al limite potrebbe kernel. Se il thread kernel si blocca, tutti i thread utente si
essere possibile pensare a scheduling/ bloccano. Non esiste parallelismo vero a livello di thread se il
gestioni personalizzate dei thread kernel gestisce solo un thread per processo, quindi senza la
all’interno di ciascun processo. gestione di thread multipli a livello di kernel. Questo significa
che anche se ci sono più thread utente, il sistema operativo
vede solo un thread "attivo" alla volta.
Se un thread rimane bloccato (ad esempio, a causa di una
system call bloccante), tutti gli altri thread nel