Insiemi thread-safe

.NET Framework 4 introduce lo spazio dei nomi System.Collections.Concurrent, il quale include diverse classi di insiemi che sono thread-safe e scalabili. Più thread possono aggiungere o rimuovere elementi da questi insiemi in modo sicuro ed efficiente senza richiedere una sincronizzazione aggiuntiva nel codice utente. Quando si scrive nuovo codice, utilizzare le classi di insiemi simultanei ogni qualvolta l'insieme scriverà contemporaneamente in più thread. In caso di semplice lettura da un insieme condiviso, è possibile utilizzare le classi nello spazio dei nomi System.Collections.Generic. Si consiglia di non utilizzare le classi di insiemi 1.0 a meno che la destinazione richiesta non sia il runtime di .NET Framework 1.1 o precedente.

Sincronizzazione dei thread negli insiemi di .NET Framework 1.0 e 2.0

Gli insiemi introdotti in .NET Framework 1.0 sono contenuti nello spazio dei nomi System.Collections. Questi insiemi, che includono gli oggetti ArrayList e Hashtable di uso comune, forniscono un buon grado di thread safety tramite la proprietà Synchronized, la quale restituisce un wrapper thread-safe per l'insieme. Il funzionamento del wrapper consiste nel bloccare l'intero insieme a ogni operazione di aggiunta o rimozione. Pertanto, ogni thread che tenta di accedere all'insieme deve attendere il proprio turno per acquisire l'unico blocco. Questo non è scalabile e può provocare un significativo calo delle prestazioni per gli insiemi di grandi dimensioni. La progettazione, inoltre, non è completamente protetta dalle race condition. Per ulteriori informazioni, vedere Sincronizzazione negli insiemi generici sul sito Web MSDN.

Le classi di insiemi introdotte in .NET Framework 2.0 sono contenute nello spazio dei nomi System.Collections.Generic. Alcuni esempi sono List<T>, Dictionary<TKey, TValue> e così via. Queste classi forniscono un'indipendenza dai tipi e prestazioni migliorate rispetto alle classi di .NET Framework 1.0. Tuttavia, le classi di insiemi di .NET Framework 2.0 non forniscono alcuna sincronizzazione dei thread; è il codice utente a dover fornire la sincronizzazione nel momento in cui vengono aggiunti o rimossi elementi in più thread contemporaneamente.

Si consigliano le classi di insiemi simultanei in .NET Framework 4 in quanto forniscono non solo l'indipendenza dai tipi delle classi di insiemi di .NET Framework 2.0, ma anche una thread safety più efficiente e completa rispetto agli insiemi di .NET Framework 1.0.

Blocco con granularità fine e meccanismi senza blocco

Alcuni tipi di insiemi simultanei utilizzano meccanismi di sincronizzazione leggeri quali SpinLock, SpinWait, SemaphoreSlim e CountdownEvent, che rappresentano una novità di .NET Framework 4. Questi tipi di sincronizzazione utilizzano in genere lo spin intenso per brevi periodi prima di impostare lo stato di attesa del thread su true. Quando si prevedono tempi di attesa molto brevi, lo spin risulta di gran lunga meno dispendioso in termini di calcolo rispetto all'attesa, che implica una transizione del kernel dispendiosa. Per le classi di insiemi che utilizzano lo spin, questa efficienza significa che più thread possono aggiungere e rimuovere elementi con una frequenza molto elevata. Per ulteriori informazioni sullo spin e il blocco, vedere SpinLock e SpinWait.

Le classi ConcurrentQueue<T> e ConcurrentStack<T> non utilizzano mai i blocchi. Al contrario, si basano su operazioni Interlocked per ottenere la thread safety.

NotaNota

Poiché le classi di insiemi simultanei supportano ICollection, forniscono le implementazioni per le proprietà IsSynchronized e SyncRoot, anche se queste proprietà sono irrilevanti.IsSynchronized restituisce sempre false e SyncRoot è sempre null (Nothing in Visual Basic).

Nella tabella riportata di seguito sono elencati i tipi di insiemi contenuti nello spazio dei nomi System.Collections.Concurrent.

Tipo

Descrizione

BlockingCollection<T>

Fornisce funzionalità di delimitazione e blocco per tutti i tipi che implementano IProducerConsumerCollection<T>. Per ulteriori informazioni, vedere Cenni preliminari su BlockingCollection.

ConcurrentDictionary<TKey, TValue>

Implementazione thread-safe di un dizionario di coppie chiave-valore.

ConcurrentQueue<T>

Implementazione thread-safe di una coda FIFO (First In First Out).

ConcurrentStack<T>

Implementazione thread-safe di uno stack LIFO (Last In First Out).

ConcurrentBag<T>

Implementazione thread-safe di un insieme non ordinato di elementi.

IProducerConsumerCollection<T>

Interfaccia che un tipo deve implementare per essere utilizzato in un oggetto BlockingCollection.

Argomenti correlati

Titolo

Descrizione

Cenni preliminari su BlockingCollection

Vengono descritte le funzionalità fornite dal tipo BlockingCollection<T>.

Procedura: aggiungere e rimuovere elementi da un oggetto ConcurrentDictionary

Viene descritto come aggiungere e rimuovere elementi da un oggetto ConcurrentDictionary<TKey, TValue>

Procedura: aggiungere e rimuovere singoli elementi di un oggetto BlockingCollection

Viene descritto come aggiungere e recuperare elementi da un insieme di blocco senza utilizzare l'enumeratore di sola lettura.

Procedura: aggiungere funzionalità di delimitazione e blocco a una classe di insiemi

Viene descritto come utilizzare una classe di insiemi come meccanismo di archiviazione sottostante per un insieme IProducerConsumerCollection<T>.

Procedura: utilizzare ForEach per rimuovere elementi in un oggetto BlockingCollection

Viene descritto come utilizzare foreach, (For Each in Visual Basic) per rimuovere tutti gli elementi in un insieme di blocco.

Procedura: utilizzare matrici di insiemi di blocco in una pipeline

Viene descritto come utilizzare più insiemi di blocco contemporaneamente per implementare una pipeline.

Procedura: creare un pool di oggetti utilizzando un oggetto ConcurrentBag

Viene illustrato come utilizzare un contenitore simultaneo per migliorare le prestazioni in scenari in cui è possibile riutilizzare oggetti anziché crearne continuamente di nuovi.

Riferimento

System.Collections.Concurrent