Pool di thread gestiti

La classe System.Threading.ThreadPool fornisce all'applicazione un pool di thread di lavoro gestiti dal sistema, per consentire di concentrarsi sulle attività dell'applicazione anziché sulla gestione dei thread. Se si dispone di attività brevi che richiedono l'elaborazione in background, il pool di thread gestiti consente di sfruttare in modo semplice i vantaggi di più thread. L'uso del pool di thread è molto più semplice in Framework 4 e versioni successive, perché è possibile creare oggetti Task e Task<TResult> che eseguono attività asincrone nei thread del pool.

.NET usa i thread del pool per numerosi scopi, tra cui operazioni Task Parallel Library (TPL), completamento I/O asincrono, callback timer, operazioni di attesa registrate, chiamate asincrone di metodi tramite delegati e connessioni socket System.Net.

Caratteristiche del pool di thread

I thread del pool sono thread in background. Ogni thread usa la dimensione dello stack predefinita, viene eseguito con la priorità predefinita e si trova in un apartment a thread multipli. Dopo il completamento dell'attività, il thread del pool torna in una coda di thread in attesa. Da questo momento il thread può essere riusato, evitando in questo modo la necessità di creare un nuovo thread per ogni attività.

È presente un solo pool di thread per processo.

Eccezioni nei thread del pool

Le eccezioni non gestite nei thread del pool terminano il processo. Sono previste tre eccezioni a questa regola:

Per altre informazioni, vedere Eccezioni in thread gestiti.

Numero massimo di thread del pool

Il numero di operazioni che possono essere accodate al pool di thread è limitato solo dalla memoria disponibile. Tuttavia il pool di thread limita il numero di thread che possono essere attivi contemporaneamente nel processo. Se tutti i thread del pool sono occupati, gli elementi di lavoro aggiuntivi vengono accodati fino a quando non tornano disponibili thread per l'esecuzione degli elementi stessi. La dimensione predefinita del pool di thread per un processo dipende da diversi fattori, ad esempio la dimensione dello spazio indirizzi virtuale. Un processo può chiamare il metodo ThreadPool.GetMaxThreads per determinare il numero di thread.

È possibile controllare il numero massimo di thread usando i metodi ThreadPool.GetMaxThreads e ThreadPool.SetMaxThreads.

Nota

Il codice che ospita Common Language Runtime può impostare la dimensione tramite il metodo ICorThreadpool::CorSetMaxThreads.

Valori minimi del pool di thread

Il pool di thread fornisce nuovi thread di lavoro o thread di completamento di I/O su richiesta fino a raggiungere un valore minimo specificato per ogni categoria. È possibile usare il metodo ThreadPool.GetMinThreads per ottenere questi valori minimi.

Nota

Quando la richiesta è bassa, il numero effettivo di thread del pool può scendere sotto i valori minimi.

Quando viene raggiunto un valore minimo, il pool di thread può creare thread aggiuntivi o attendere il completamento di alcune attività. Il pool di thread crea ed elimina definitivamente i thread di lavoro per ottimizzare la velocità effettiva, definita come numero di attività completate per unità di tempo. Un numero troppo ridotto di thread potrebbe non usare in modo ottimale le risorse disponibili, mentre troppi thread potrebbero aumentare il conflitto per le risorse.

Attenzione

È possibile usare il metodo ThreadPool.SetMinThreads per aumentare il numero minimo di thread inattivi. Tuttavia, un aumento non necessario di questi valori può provocare problemi di prestazioni. Se si avviano troppe attività contemporaneamente, potrebbero sembrare tutte lente. Nella maggior parte dei casi, il pool di thread offre prestazioni migliori con il proprio algoritmo per l'allocazione dei thread.

Uso del pool di thread

Il modo più semplice per usare il pool di thread consiste nell'usare Task Parallel Library (TPL). Per impostazione predefinita i tipi TPL come Task e Task<TResult> usano i thread del pool per eseguire le attività.

È anche possibile usare il pool di thread chiamando ThreadPool.QueueUserWorkItem dal codice gestito (o ICorThreadpool::CorQueueUserWorkItem dal codice non gestito) e passando un delegato System.Threading.WaitCallback che rappresenta il metodo che esegue l'attività.

Un altro metodo per usare il pool di thread consiste nell'accodare gli elementi di lavoro correlati a un'operazione di attesa usando il metodo ThreadPool.RegisterWaitForSingleObject e passando un oggetto System.Threading.WaitHandle che, quando viene segnalato o in caso di time out, chiama il metodo rappresentato dal delegato System.Threading.WaitOrTimerCallback. I thread del pool vengono usati per richiamare i metodi di callback.

Per esempi, vedere le pagine delle API di riferimento.

Ignorare i controlli di sicurezza

Il pool di thread fornisce anche i metodi ThreadPool.UnsafeQueueUserWorkItem e ThreadPool.UnsafeRegisterWaitForSingleObject. Usare questi metodi solo quando si è certi che lo stack del chiamante non sia rilevante per i controlli di sicurezza svolti durante l'esecuzione dell'attività in coda. I metodi ThreadPool.QueueUserWorkItem e ThreadPool.RegisterWaitForSingleObject consentono entrambi di acquisire lo stack del chiamante, che viene unito nello stack del thread del pool quando il thread inizia a eseguire un'attività. Se è necessario un controllo di sicurezza, deve essere controllato l'intero stack. Sebbene il controllo garantisca la sicurezza, comporta anche una riduzione delle prestazioni.

Quando non usare i thread del pool

Vi sono diversi scenari in cui è opportuno creare e gestire i propri thread anziché usare i thread del pool, come nei casi seguenti:

  • È necessario un thread in primo piano.
  • È necessario che un thread abbia una priorità specifica.
  • Sono presenti attività che causano il blocco del thread per lunghi periodi di tempo. Il pool di thread prevede un numero massimo di thread, pertanto un numero elevato di thread del pool bloccati potrebbe impedire l'avvio delle attività.
  • È necessario inserire thread di un apartment a thread singolo. Tutti i thread di ThreadPool sono inclusi in apartment a thread multipli.
  • È necessario disporre di un'identità stabile associata al thread o dedicare un thread a un'attività.

Vedi anche