Archiviazione locale del thread: slot di dati e campi statici relativi ai thread
È possibile usare l'archiviazione thread-local gestita per archiviare dati univoci relativi a un thread e un dominio dell'applicazione. In .NET sono disponibili due strumenti per usare l'archiviazione thread-local gestita: i campi statici relativi ai thread e gli slot di dati.
Usare i campi statici relativi ai thread (campi
Shared
relativi ai thread in Visual Basic) se è possibile prevedere con esattezza le esigenze in fase di compilazione. I campi statici relativi ai thread forniscono infatti prestazioni ottimali. Offrono inoltre il vantaggio di poter controllare il tipo in fase di compilazione.Se i requisiti effettivi possono essere individuati solo in fase di runtime, usare gli slot di dati. Gli slot di dati sono più lenti e scomodi da usare rispetto ai campi statici relativi ai thread e i dati vengono archiviati come tipo Object. Prima di usarli, quindi, è necessario eseguirne il cast al tipo corretto.
In C++ non gestito si usa TlsAlloc
per allocare gli slot dinamicamente e __declspec(thread)
per dichiarare che una variabile deve essere allocata in una risorsa di archiviazione relativa ai thread. I campi statici relativi ai thread e gli slot di dati forniscono la versione gestita di questo comportamento.
È possibile usare la classe System.Threading.ThreadLocal<T> per creare oggetti locali di thread inizializzati in modo differito quando l'oggetto viene usato per la prima volta. Per altre informazioni, vedere Inizializzazione differita.
Unicità dei dati nell'archiviazione locale dei thread gestiti
Indipendentemente dal fatto che si usino i campi statici relativi ai thread o gli slot di dati, i dati presenti nell'archiviazione locale dei thread gestiti sono univoci per la combinazione di thread e dominio dell'applicazione.
All'interno di un dominio dell'applicazione, un thread non può modificare dati provenienti da un altro thread, anche se usano entrambi lo stesso campo o slot.
Quando un thread accede allo stesso campo o slot da più domini dell'applicazione, viene mantenuto un valore separato in ogni dominio dell'applicazione.
Se, ad esempio, un thread imposta il valore di un campo statico relativo al thread, immette un altro dominio dell'applicazione e quindi recupera il valore del campo, il valore recuperato nel secondo dominio dell'applicazione differisce dal valore presente nel primo dominio dell'applicazione. L'impostazione di un nuovo valore per il campo nel secondo dominio dell'applicazione non influisce sul valore del campo nel primo dominio dell'applicazione.
Analogamente, se un thread ottiene lo stesso slot di dati denominato in due domini dell'applicazione diversi, i dati nel primo dominio dell'applicazione restano indipendenti dai dati presenti nel secondo dominio dell'applicazione.
Campi statici relativi ai thread
Se si è certi che i dati sono sempre univoci in una combinazione di thread e dominio dell'applicazione, applicare l'attributo ThreadStaticAttribute al campo statico. Usare il campo come qualsiasi altro campo statico. I dati nel campo sono univoci di ogni thread che li usa.
I campi statici relativi ai thread garantiscono prestazioni migliori rispetto agli slot di dati e offrono il vantaggio di poter controllare il tipo in fase di compilazione.
Tenere presente che qualsiasi codice del costruttore di classe verrà eseguito sul primo thread nel primo contesto che accede al campo. In tutti gli altri thread o contesti nello stesso dominio dell'applicazione i campi verranno inizializzati su null
(Nothing
in Visual Basic) se sono tipi di riferimento o sui valori predefiniti se sono tipi valore. Di conseguenza, non è consigliabile basarsi sui costruttori delle classi per inizializzare i campi statici relativi ai thread. Al contrario, è opportuno evitare l'inizializzazione di campi statici relativi ai thread e supporre che vengano inizializzati su null
(Nothing
) o sui valori predefiniti.
Slot dei dati
.NET fornisce slot di dati dinamici univoci per ogni combinazione di thread e dominio dell'applicazione. Esistono due tipi di slot di dati: con e senza nome. Entrambi vengono implementati usando la struttura LocalDataStoreSlot.
Per creare uno slot di dati con nome, usare il metodo Thread.AllocateNamedDataSlot o Thread.GetNamedDataSlot. Per ottenere un riferimento a uno slot con nome esistente, passare il nome al metodo GetNamedDataSlot.
Per creare uno slot di dati senza nome, usare il metodo Thread.AllocateDataSlot.
Per entrambi i tipo di slot, con e senza nome, usare i metodi Thread.SetData e Thread.GetData per impostare e recuperare le informazioni nello slot. Si tratta di metodi statici che agiscono sempre sui dati per il thread che li sta eseguendo.
Gli slot con nome offrono la comodità di poter essere recuperati in qualsiasi momento passandone il nome al metodo GetNamedDataSlot, anziché mantenere un riferimento a uno slot senza nome. Se, tuttavia, un altro componente usa lo stesso nome per la risorsa di archiviazione relativa ai thread e un thread esegue codice sia dal componente in uso che dall'altro componente, i due componenti possono danneggiare l'uno i dati dell'altro. Questo scenario presuppone che entrambi i componenti siano in esecuzione nello stesso dominio dell'applicazione e che non siano progettati per condividere gli stessi dati.