ThreadStaticAttribute Classe
Definição
Importante
Algumas informações se referem a produtos de pré-lançamento que podem ser substancialmente modificados antes do lançamento. A Microsoft não oferece garantias, expressas ou implícitas, das informações aqui fornecidas.
Indica se o valor de um campo estático é exclusivo para cada 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
- Herança
- Atributos
Exemplos
O exemplo a seguir cria um gerador de número aleatório, cria dez threads além do thread principal e gera dois milhões de números aleatórios em cada thread. Ele usa o ThreadStaticAttribute atributo para calcular a soma e a contagem de números aleatórios por thread. Ele também define dois campos previous
adicionais por thread e abnormal
, que permite detectar corrupção do gerador de número aleatório.
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.
O exemplo usa a lock
instrução em C#, a lock
função em F#e o SyncLock
constructo em Visual Basic para sincronizar o acesso ao gerador de número aleatório. Isso evita a corrupção do gerador de número aleatório, o que normalmente resulta no retorno de um valor zero para todas as chamadas subsequentes.
O exemplo também usa a CountdownEvent classe para garantir que cada thread tenha terminado de gerar números aleatórios antes de exibir o número total de chamadas. Caso contrário, se o thread principal concluir a execução antes dos threads adicionais gerados, ele exibirá um valor impreciso para o número total de chamadas de método.
Comentários
Um static
campo marcado com ThreadStaticAttribute não é compartilhado entre threads. Cada thread em execução tem uma instância separada do campo e define e obtém valores independentemente para esse campo. Se o campo for acessado em um thread diferente, ele conterá um valor diferente.
Observe que, além de aplicar o ThreadStaticAttribute atributo a um campo, você também deve defini-lo como um static
campo (em C# ou F#) ou um Shared
campo (em Visual Basic).
Observação
Não especifique valores iniciais para campos marcados com ThreadStaticAttribute
, porque essa inicialização ocorre apenas uma vez, quando o construtor de classe é executado e, portanto, afeta apenas um thread. Se você não especificar um valor inicial, poderá contar com o campo sendo inicializado para seu valor padrão se for um tipo de valor ou se null
for um tipo de referência.
Use esse atributo como ele é e não derive dele.
Para obter mais informações sobre como usar atributos, consulte Atributos.
Construtores
ThreadStaticAttribute() |
Inicializa uma nova instância da classe ThreadStaticAttribute. |
Propriedades
TypeId |
Quando implementado em uma classe derivada, obtém um identificador exclusivo para este Attribute. (Herdado de Attribute) |
Métodos
Equals(Object) |
Retorna um valor que indica se essa instância é igual a um objeto especificado. (Herdado de Attribute) |
GetHashCode() |
Retorna o código hash para a instância. (Herdado de Attribute) |
GetType() |
Obtém o Type da instância atual. (Herdado de Object) |
IsDefaultAttribute() |
Quando substituído em uma classe derivada, indica se o valor dessa instância é o valor padrão para a classe derivada. (Herdado de Attribute) |
Match(Object) |
Quando substituído em uma classe derivada, retorna um valor que indica se essa instância é igual a um objeto especificado. (Herdado de Attribute) |
MemberwiseClone() |
Cria uma cópia superficial do Object atual. (Herdado de Object) |
ToString() |
Retorna uma cadeia de caracteres que representa o objeto atual. (Herdado de Object) |
Implantações explícitas de interface
_Attribute.GetIDsOfNames(Guid, IntPtr, UInt32, UInt32, IntPtr) |
Mapeia um conjunto de nomes para um conjunto correspondente de identificadores de expedição. (Herdado de Attribute) |
_Attribute.GetTypeInfo(UInt32, UInt32, IntPtr) |
Recupera as informações de tipo para um objeto, que pode ser usado para obter as informações de tipo para uma interface. (Herdado de Attribute) |
_Attribute.GetTypeInfoCount(UInt32) |
Retorna o número de interfaces de informações do tipo que um objeto fornece (0 ou 1). (Herdado de Attribute) |
_Attribute.Invoke(UInt32, Guid, UInt32, Int16, IntPtr, IntPtr, IntPtr, IntPtr) |
Fornece acesso a propriedades e métodos expostos por um objeto. (Herdado de Attribute) |