ThreadStaticAttribute Classe
Definizione
Importante
Alcune informazioni sono relative alla release non definitiva del prodotto, che potrebbe subire modifiche significative prima della release definitiva. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Indica che il valore di un campo statico è univoco per ogni thread.
public ref class ThreadStaticAttribute : Attribute
[System.AttributeUsage(System.AttributeTargets.Field, Inherited=false)]
public class ThreadStaticAttribute : Attribute
[System.AttributeUsage(System.AttributeTargets.Field, Inherited=false)]
[System.Serializable]
public class ThreadStaticAttribute : Attribute
[System.AttributeUsage(System.AttributeTargets.Field, Inherited=false)]
[System.Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public class ThreadStaticAttribute : Attribute
[<System.AttributeUsage(System.AttributeTargets.Field, Inherited=false)>]
type ThreadStaticAttribute = class
inherit Attribute
[<System.AttributeUsage(System.AttributeTargets.Field, Inherited=false)>]
[<System.Serializable>]
type ThreadStaticAttribute = class
inherit Attribute
[<System.AttributeUsage(System.AttributeTargets.Field, Inherited=false)>]
[<System.Serializable>]
[<System.Runtime.InteropServices.ComVisible(true)>]
type ThreadStaticAttribute = class
inherit Attribute
Public Class ThreadStaticAttribute
Inherits Attribute
- Ereditarietà
- Attributi
Esempio
Nell'esempio seguente viene creata un'istanza di un generatore di numeri casuali, vengono creati 10 thread oltre al thread principale ed infine vengono generati due milioni di numeri casuali in ogni thread. Utilizza l'attributo ThreadStaticAttribute per calcolare la somma e il conteggio dei numeri casuali per ogni thread. Definisce inoltre due campi aggiuntivi per ogni singolo thread, previous
e abnormal
per rilevare il danneggiamento del generatore di numeri casuali.
using System;
using System.Threading;
public class Example
{
[ThreadStatic] static double previous = 0.0;
[ThreadStatic] static double sum = 0.0;
[ThreadStatic] static int calls = 0;
[ThreadStatic] static bool abnormal;
static int totalNumbers = 0;
static CountdownEvent countdown;
private static Object lockObj;
Random rand;
public Example()
{
rand = new Random();
lockObj = new Object();
countdown = new CountdownEvent(1);
}
public static void Main()
{
Example ex = new Example();
Thread.CurrentThread.Name = "Main";
ex.Execute();
countdown.Wait();
Console.WriteLine("{0:N0} random numbers were generated.", totalNumbers);
}
private void Execute()
{
for (int threads = 1; threads <= 10; threads++)
{
Thread newThread = new Thread(new ThreadStart(this.GetRandomNumbers));
countdown.AddCount();
newThread.Name = threads.ToString();
newThread.Start();
}
this.GetRandomNumbers();
}
private void GetRandomNumbers()
{
double result = 0.0;
for (int ctr = 0; ctr < 2000000; ctr++)
{
lock (lockObj) {
result = rand.NextDouble();
calls++;
Interlocked.Increment(ref totalNumbers);
// We should never get the same random number twice.
if (result == previous) {
abnormal = true;
break;
}
else {
previous = result;
sum += result;
}
}
}
// get last result
if (abnormal)
Console.WriteLine("Result is {0} in {1}", previous, Thread.CurrentThread.Name);
Console.WriteLine("Thread {0} finished random number generation.", Thread.CurrentThread.Name);
Console.WriteLine("Sum = {0:N4}, Mean = {1:N4}, n = {2:N0}\n", sum, sum/calls, calls);
countdown.Signal();
}
}
// The example displays output similar to the following:
// Thread 1 finished random number generation.
// Sum = 1,000,556.7483, Mean = 0.5003, n = 2,000,000
//
// Thread 6 finished random number generation.
// Sum = 999,704.3865, Mean = 0.4999, n = 2,000,000
//
// Thread 2 finished random number generation.
// Sum = 999,680.8904, Mean = 0.4998, n = 2,000,000
//
// Thread 10 finished random number generation.
// Sum = 999,437.5132, Mean = 0.4997, n = 2,000,000
//
// Thread 8 finished random number generation.
// Sum = 1,000,663.7789, Mean = 0.5003, n = 2,000,000
//
// Thread 4 finished random number generation.
// Sum = 999,379.5978, Mean = 0.4997, n = 2,000,000
//
// Thread 5 finished random number generation.
// Sum = 1,000,011.0605, Mean = 0.5000, n = 2,000,000
//
// Thread 9 finished random number generation.
// Sum = 1,000,637.4556, Mean = 0.5003, n = 2,000,000
//
// Thread Main finished random number generation.
// Sum = 1,000,676.2381, Mean = 0.5003, n = 2,000,000
//
// Thread 3 finished random number generation.
// Sum = 999,951.1025, Mean = 0.5000, n = 2,000,000
//
// Thread 7 finished random number generation.
// Sum = 1,000,844.5217, Mean = 0.5004, n = 2,000,000
//
// 22,000,000 random numbers were generated.
open System
open System.Threading
type Example() =
[<ThreadStatic; DefaultValue>]
static val mutable private previous : double
[<ThreadStatic; DefaultValue>]
static val mutable private sum : double
[<ThreadStatic; DefaultValue>]
static val mutable private calls : int
[<ThreadStatic; DefaultValue>]
static val mutable private abnormal : bool
static let mutable totalNumbers = 0
static let countdown = new CountdownEvent(1)
static let lockObj = obj ()
let rand = Random()
member this.Execute() =
for threads = 1 to 10 do
let newThread = new Thread(ThreadStart this.GetRandomNumbers)
countdown.AddCount()
newThread.Name <- threads.ToString()
newThread.Start()
this.GetRandomNumbers()
countdown.Wait()
printfn $"{totalNumbers:N0} random numbers were generated."
member _.GetRandomNumbers() =
let mutable i = 0
while i < 2000000 do
lock lockObj (fun () ->
let result = rand.NextDouble()
Example.calls <- Example.calls + 1
Interlocked.Increment &totalNumbers |> ignore
// We should never get the same random number twice.
if result = Example.previous then
Example.abnormal <- true
i <- 2000001 // break
else
Example.previous <- result
Example.sum <- Example.sum + result )
i <- i + 1
// get last result
if Example.abnormal then
printfn $"Result is {Example.previous} in {Thread.CurrentThread.Name}"
printfn $"Thread {Thread.CurrentThread.Name} finished random number generation."
printfn $"Sum = {Example.sum:N4}, Mean = {Example.sum / float Example.calls:N4}, n = {Example.calls:N0}\n"
countdown.Signal() |> ignore
let ex = Example()
Thread.CurrentThread.Name <- "Main"
ex.Execute()
// The example displays output similar to the following:
// Thread 1 finished random number generation.
// Sum = 1,000,556.7483, Mean = 0.5003, n = 2,000,000
//
// Thread 6 finished random number generation.
// Sum = 999,704.3865, Mean = 0.4999, n = 2,000,000
//
// Thread 2 finished random number generation.
// Sum = 999,680.8904, Mean = 0.4998, n = 2,000,000
//
// Thread 10 finished random number generation.
// Sum = 999,437.5132, Mean = 0.4997, n = 2,000,000
//
// Thread 8 finished random number generation.
// Sum = 1,000,663.7789, Mean = 0.5003, n = 2,000,000
//
// Thread 4 finished random number generation.
// Sum = 999,379.5978, Mean = 0.4997, n = 2,000,000
//
// Thread 5 finished random number generation.
// Sum = 1,000,011.0605, Mean = 0.5000, n = 2,000,000
//
// Thread 9 finished random number generation.
// Sum = 1,000,637.4556, Mean = 0.5003, n = 2,000,000
//
// Thread Main finished random number generation.
// Sum = 1,000,676.2381, Mean = 0.5003, n = 2,000,000
//
// Thread 3 finished random number generation.
// Sum = 999,951.1025, Mean = 0.5000, n = 2,000,000
//
// Thread 7 finished random number generation.
// Sum = 1,000,844.5217, Mean = 0.5004, n = 2,000,000
//
// 22,000,000 random numbers were generated.
Imports System.Threading
Public Class Example
<ThreadStatic> Shared previous As Double = 0.0
<ThreadStatic> Shared sum As Double = 0.0
<ThreadStatic> Shared calls As Integer = 0
<ThreadStatic> Shared abnormal As Boolean
Shared totalNumbers As Integer = 0
Shared countdown As CountdownEvent
Private Shared lockObj As Object
Dim rand As Random
Public Sub New()
rand = New Random()
lockObj = New Object()
countdown = New CountdownEvent(1)
End Sub
Public Shared Sub Main()
Dim ex As New Example()
Thread.CurrentThread.Name = "Main"
ex.Execute()
countdown.Wait()
Console.WriteLine("{0:N0} random numbers were generated.", totalNumbers)
End Sub
Private Sub Execute()
For threads As Integer = 1 To 10
Dim newThread As New Thread(New ThreadStart(AddressOf GetRandomNumbers))
countdown.AddCount()
newThread.Name = threads.ToString()
newThread.Start()
Next
Me.GetRandomNumbers()
End Sub
Private Sub GetRandomNumbers()
Dim result As Double = 0.0
For ctr As Integer = 1 To 2000000
SyncLock lockObj
result = rand.NextDouble()
calls += 1
Interlocked.Increment(totalNumbers)
' We should never get the same random number twice.
If result = previous Then
abnormal = True
Exit For
Else
previous = result
sum += result
End If
End SyncLock
Next
' Get last result.
If abnormal Then
Console.WriteLine("Result is {0} in {1}", previous, Thread.CurrentThread.Name)
End If
Console.WriteLine("Thread {0} finished random number generation.", Thread.CurrentThread.Name)
Console.WriteLine("Sum = {0:N4}, Mean = {1:N4}, n = {2:N0}", sum, sum/calls, calls)
Console.WriteLine()
countdown.Signal()
End Sub
End Class
' The example displays output similar to the following:
' Thread 1 finished random number generation.
' Sum = 1,000,556.7483, Mean = 0.5003, n = 2,000,000
'
' Thread 6 finished random number generation.
' Sum = 999,704.3865, Mean = 0.4999, n = 2,000,000
'
' Thread 2 finished random number generation.
' Sum = 999,680.8904, Mean = 0.4998, n = 2,000,000
'
' Thread 10 finished random number generation.
' Sum = 999,437.5132, Mean = 0.4997, n = 2,000,000
'
' Thread 8 finished random number generation.
' Sum = 1,000,663.7789, Mean = 0.5003, n = 2,000,000
'
' Thread 4 finished random number generation.
' Sum = 999,379.5978, Mean = 0.4997, n = 2,000,000
'
' Thread 5 finished random number generation.
' Sum = 1,000,011.0605, Mean = 0.5000, n = 2,000,000
'
' Thread 9 finished random number generation.
' Sum = 1,000,637.4556, Mean = 0.5003, n = 2,000,000
'
' Thread Main finished random number generation.
' Sum = 1,000,676.2381, Mean = 0.5003, n = 2,000,000
'
' Thread 3 finished random number generation.
' Sum = 999,951.1025, Mean = 0.5000, n = 2,000,000
'
' Thread 7 finished random number generation.
' Sum = 1,000,844.5217, Mean = 0.5004, n = 2,000,000
'
' 22,000,000 random numbers were generated.
Nell'esempio viene usata l'istruzione lock
in C#, la lock
funzione in F# e il SyncLock
costrutto in Visual Basic per sincronizzare l'accesso al generatore di numeri casuali. Ciò impedisce il danneggiamento del generatore di numeri casuali, che in genere comporta la restituzione del valore zero per tutte le chiamate successive.
Nell'esempio viene anche utilizzata la classe CountdownEvent per garantire che la generazione di numeri casuali sia stata completata da ogni thread prima che venga visualizzato il numero totale di chiamate. In caso contrario, se il thread principale viene completato prima degli altri thread generati, viene visualizzato un valore impreciso relativo al numero totale di chiamate al metodo.
Commenti
Un static
campo contrassegnato con ThreadStaticAttribute non è condiviso tra thread. Ogni thread in esecuzione ha un'istanza separata del campo e imposta in modo indipendente e ottiene i valori per tale campo. Se si accede al campo in un thread diverso, conterrà un valore diverso.
Si noti che, oltre ad applicare l'attributo ThreadStaticAttribute a un campo, è necessario definirlo anche come static
campo (in C# o F#) o Shared
come campo (in Visual Basic).
Nota
Non specificare i valori iniziali per i campi contrassegnati con ThreadStaticAttribute
, perché tale inizializzazione si verifica una sola volta, quando il costruttore della classe viene eseguito e pertanto influisce su un solo thread. Se non si specifica un valore iniziale, è possibile fare affidamento sul campo inizializzato sul relativo valore predefinito se è un tipo di valore o su null
se è un tipo riferimento.
Usare questo attributo così come è e non derivare da esso.
Per altre informazioni sull'uso degli attributi, vedere Attributi.
Costruttori
ThreadStaticAttribute() |
Inizializza una nuova istanza della classe ThreadStaticAttribute. |
Proprietà
TypeId |
Quando è implementata in una classe derivata, ottiene un identificatore univoco della classe Attribute. (Ereditato da Attribute) |
Metodi
Equals(Object) |
Restituisce un valore che indica se questa istanza è uguale a un oggetto specificato. (Ereditato da Attribute) |
GetHashCode() |
Restituisce il codice hash per l'istanza. (Ereditato da Attribute) |
GetType() |
Ottiene l'oggetto Type dell'istanza corrente. (Ereditato da Object) |
IsDefaultAttribute() |
In caso di override in una classe derivata, indica se il valore di questa istanza è il valore predefinito per la classe derivata. (Ereditato da Attribute) |
Match(Object) |
Quando è sottoposto a override in una classe derivata, restituisce un valore che indica se questa istanza equivale a un oggetto specificato. (Ereditato da Attribute) |
MemberwiseClone() |
Crea una copia superficiale dell'oggetto Object corrente. (Ereditato da Object) |
ToString() |
Restituisce una stringa che rappresenta l'oggetto corrente. (Ereditato da Object) |
Implementazioni dell'interfaccia esplicita
_Attribute.GetIDsOfNames(Guid, IntPtr, UInt32, UInt32, IntPtr) |
Esegue il mapping di un set di nomi a un set corrispondente di ID dispatch. (Ereditato da Attribute) |
_Attribute.GetTypeInfo(UInt32, UInt32, IntPtr) |
Recupera le informazioni sul tipo relative a un oggetto, che possono essere usate per ottenere informazioni sul tipo relative a un'interfaccia. (Ereditato da Attribute) |
_Attribute.GetTypeInfoCount(UInt32) |
Recupera il numero delle interfacce di informazioni sul tipo fornite da un oggetto (0 o 1). (Ereditato da Attribute) |
_Attribute.Invoke(UInt32, Guid, UInt32, Int16, IntPtr, IntPtr, IntPtr, IntPtr) |
Fornisce l'accesso a proprietà e metodi esposti da un oggetto. (Ereditato da Attribute) |