ThreadStaticAttribute Classe
Définition
Important
Certaines informations portent sur la préversion du produit qui est susceptible d’être en grande partie modifiée avant sa publication. Microsoft exclut toute garantie, expresse ou implicite, concernant les informations fournies ici.
Indique que la valeur d'un champ statique est unique pour chaque 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
- Héritage
- Attributs
Exemples
L’exemple suivant instancie un générateur de nombres aléatoires, crée dix threads en plus du thread principal, puis génère deux millions de nombres aléatoires dans chaque thread. Il utilise l’attribut pour calculer la ThreadStaticAttribute somme et le nombre de nombres aléatoires par thread. Il définit également deux champs supplémentaires par thread et previous
abnormal
, ce qui lui permet de détecter l’altération du générateur de nombres aléatoires.
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.
L’exemple utilise l’instruction lock
C#, la lock
fonction en F#et la SyncLock
construction dans Visual Basic pour synchroniser l’accès au générateur de nombres aléatoires. Cela empêche l’altération du générateur de nombres aléatoires, ce qui entraîne généralement son retour d’une valeur de zéro pour tous les appels suivants.
L’exemple utilise également la CountdownEvent classe pour s’assurer que chaque thread a fini de générer des nombres aléatoires avant d’afficher le nombre total d’appels. Sinon, si le thread principal termine l’exécution avant les threads supplémentaires qu’il génère, il affiche une valeur inexacte pour le nombre total d’appels de méthode.
Remarques
Un static
champ marqué avec ThreadStaticAttribute n’est pas partagé entre les threads. Chaque thread en cours d’exécution a une instance distincte du champ et définit et obtient des valeurs pour ce champ. Si le champ est accessible sur un autre thread, il contient une valeur différente.
Notez que, en plus d’appliquer l’attribut ThreadStaticAttribute à un champ, vous devez également le définir comme un static
champ (en C# ou F#) ou un Shared
champ (dans Visual Basic).
Notes
Ne spécifiez pas de valeurs initiales pour les champs marqués avec ThreadStaticAttribute
, car cette initialisation ne se produit qu’une seule fois, lorsque le constructeur de classe s’exécute, et affecte donc un seul thread. Si vous ne spécifiez pas de valeur initiale, vous pouvez vous appuyer sur le champ initialisé sur sa valeur par défaut s’il s’agit d’un type de valeur ou null
s’il s’agit d’un type de référence.
Utilisez cet attribut comme c’est le cas et ne dérivez pas de celui-ci.
Pour plus d’informations sur l’utilisation d’attributs, consultez Attributs.
Constructeurs
ThreadStaticAttribute() |
Initialise une nouvelle instance de la classe ThreadStaticAttribute. |
Propriétés
TypeId |
Lors de l'implémentation dans une classe dérivée, obtient un identificateur unique pour l'objet Attribute. (Hérité de Attribute) |
Méthodes
Equals(Object) |
Retourne une valeur qui indique si cette instance est égale à un objet spécifié. (Hérité de Attribute) |
GetHashCode() |
Retourne le code de hachage de cette instance. (Hérité de Attribute) |
GetType() |
Obtient le Type de l'instance actuelle. (Hérité de Object) |
IsDefaultAttribute() |
En cas de substitution dans une classe dérivée, indique si la valeur de cette instance est la valeur par défaut pour la classe dérivée. (Hérité de Attribute) |
Match(Object) |
En cas de substitution dans une classe dérivée, retourne une valeur indiquant si cette instance équivaut à un objet spécifié. (Hérité de Attribute) |
MemberwiseClone() |
Crée une copie superficielle du Object actuel. (Hérité de Object) |
ToString() |
Retourne une chaîne qui représente l'objet actuel. (Hérité de Object) |
Implémentations d’interfaces explicites
_Attribute.GetIDsOfNames(Guid, IntPtr, UInt32, UInt32, IntPtr) |
Mappe un jeu de noms avec un jeu correspondant d'identificateurs de dispatch. (Hérité de Attribute) |
_Attribute.GetTypeInfo(UInt32, UInt32, IntPtr) |
Récupère les informations de type pour un objet, qui peuvent être utilisées pour obtenir les informations de type d'une interface. (Hérité de Attribute) |
_Attribute.GetTypeInfoCount(UInt32) |
Récupère le nombre d'interfaces d'informations de type fourni par un objet (0 ou 1). (Hérité de Attribute) |
_Attribute.Invoke(UInt32, Guid, UInt32, Int16, IntPtr, IntPtr, IntPtr, IntPtr) |
Fournit l'accès aux propriétés et aux méthodes exposées par un objet. (Hérité de Attribute) |