Le discussioni emergono in due prospettive: sistemi operativi e linguaggi di programmazione. In entrambi i casi, c'è qualche variazione negli attributi di un thread.
Una definizione minima di un thread è che è roba che accade in sequenza, una cosa dopo l'altra.
In un tipico modello di esecuzione della macchina, ogni thread ha il proprio set di registri di uso generale e il proprio contatore di programmi. Se la macchina imposta un registro specifico come puntatore di stack, c'è una copia per thread.
Dal punto di vista del sistema operativo, il minimo che un sistema operativo deve fare per supportare i thread è fornire un modo per passare da uno all'altro. Ciò può avvenire automaticamente ( multitasking preventivo o solo quando il thread formula una richiesta esplicita (multitasking cooperativo; in tal caso i thread vengono talvolta chiamati fibre ). Esistono anche modelli ibridi con prelazione sia preventiva che cooperativa, ad es. Prelazione tra thread di gruppi diversi o attività ma rendimenti espliciti tra thread dello stesso gruppo / attività. Il passaggio tra thread implica almeno il salvataggio dei valori di registro del thread precedente e il ripristino dei valori di registro del nuovo thread.
In un sistema operativo multitasking che fornisce isolamento tra attività (o processi , è possibile trattare questi termini come sinonimi in un contesto di sistema operativo), ogni attività ha le proprie risorse, in particolare lo spazio degli indirizzi, ma anche file aperti, privilegi, ecc. L'isolamento ha deve essere fornito dal kernel del sistema operativo , un'entità che è al di sopra dei processi. Ogni attività ha normalmente almeno un thread - un'attività che non esegue il codice non è di grande utilità. Il sistema operativo può o meno supportare più thread nella stessa attività; ad esempio Unix originale no. Un'attività può ancora eseguire più thread organizzando il passaggio tra di essi - questo non richiede alcun privilegio speciale. Questo si chiama " thread utente", Specialmente in un contesto Unix. Oggi la maggior parte dei sistemi Unix fornisce thread del kernel, in particolare perché è l'unico modo per avere più thread dello stesso processo in esecuzione su processori diversi.
La maggior parte delle risorse del sistema operativo, a parte il tempo di calcolo, sono associate alle attività, non ai thread. Alcuni sistemi operativi (ad esempio Linux) delimitano esplicitamente gli stack, nel qual caso ogni thread ha il suo; ma ci sono sistemi operativi in cui il kernel non sa nulla degli stack, fanno solo parte dell'heap per quanto riguarda. Il kernel in genere gestisce anche un contesto del kernel per ogni thread, che è una struttura di dati contenente informazioni su ciò che il thread sta attualmente facendo; questo consente al kernel di gestire più thread bloccati in una chiamata di sistema contemporaneamente.
Per quanto riguarda il sistema operativo, i thread di un'attività eseguono lo stesso codice, ma si trovano in posizioni diverse in quel codice (valori del contatore del programma diversi). Può capitare o no che alcune parti del codice di un programma vengano sempre eseguite in thread specifici, ma di solito esiste un codice comune (ad es. Funzioni di utilità) che può essere chiamato da qualsiasi thread. Tutti i thread vedono gli stessi dati, altrimenti sarebbero considerati compiti diversi; se alcuni dati sono accessibili solo da un determinato thread, di solito è solo la competenza del linguaggio di programmazione, non del sistema operativo.
Nella maggior parte dei linguaggi di programmazione, l'archiviazione è condivisa tra thread dello stesso programma. Questo è un modello di memoria condivisa di programmazione concorrente; è molto popolare, ma anche molto soggetto a errori, perché il programmatore deve fare attenzione quando è possibile accedere agli stessi dati da più thread poiché possono verificarsi condizioni di competizione . Nota che anche le variabili locali possono essere condivise tra thread: "variabile locale" (di solito) significa una variabile il cui nome è valido solo durante un'esecuzione di una funzione, ma un altro thread può ottenere un puntatore a quella variabile e accedervi.
Esistono anche linguaggi di programmazione in cui ogni thread ha la propria memoria e la comunicazione tra di essi avviene inviando messaggi sui canali di comunicazione. Questo è il modello di passaggio dei messaggi di programmazione concorrente. Erlangè il principale linguaggio di programmazione che si concentra sul passaggio dei messaggi; il suo ambiente di esecuzione ha una gestione dei thread molto leggera e incoraggia i programmi scritti con molti thread di breve durata, in contrasto con la maggior parte degli altri linguaggi di programmazione in cui la creazione di un thread è un'operazione relativamente costosa e l'ambiente di runtime non può supportare una dimensione molto grande numero di thread contemporaneamente. Il sottoinsieme sequenziale di Erlang (la parte del linguaggio che accade all'interno di un thread, in particolare la manipolazione dei dati) è (principalmente) puramente funzionale; pertanto un thread può inviare un messaggio a un altro thread contenente alcuni dati e nessuno dei due thread deve preoccuparsi che i dati vengano modificati dall'altro thread mentre lo sta utilizzando.
Alcune lingue combinano i due modelli offrendo uno storage thread-local, con o senza un sistema di tipi per distinguere la posizione dello storage thread-local da quelli globali. L'archiviazione locale di thread è in genere una funzionalità utile che consente a un nome di variabile di designare posizioni di archiviazione diverse in thread diversi.
Alcuni (difficili) follow-up che potrebbero essere di interesse per capire quali thread sono:
- Qual è il minimo che un kernel deve fare per supportare più thread?
- In un ambiente multiprocessore, cosa serve per migrare un thread da un processore a un altro?
- Cosa sarebbe necessario per implementare il multithreading cooperativo ( coroutine ) nel tuo linguaggio di programmazione preferito senza il supporto del sistema operativo e senza utilizzare il suo supporto integrato? (Attenzione che la maggior parte dei linguaggi di programmazione non ha le primitive necessarie per implementare le coroutine all'interno di un singolo thread.)
- Come potrebbe essere un linguaggio di programmazione se avesse una concorrenza ma nessun concetto (esplicito) di thread? (Primo esempio: il pi-calculus .)