ThreadStaticAttribute Clase

Definición

Indica que el valor de un campo estático es único para cada subproceso.

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
Herencia
ThreadStaticAttribute
Atributos

Ejemplos

En el ejemplo siguiente se crea una instancia de un generador de números aleatorios, se crean diez subprocesos además del subproceso principal y, a continuación, se generan dos millones de números aleatorios en cada subproceso. Usa el ThreadStaticAttribute atributo para calcular la suma y el recuento de números aleatorios por subproceso. También define dos campos adicionales por subproceso y previous abnormal, que le permite detectar daños en el generador de números aleatorios.

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.

En el ejemplo se usa la lock instrucción en C#, la lock función en F#, y la SyncLock construcción de Visual Basic para sincronizar el acceso al generador de números aleatorios. Esto evita daños en el generador de números aleatorios, lo que normalmente da como resultado que devuelva un valor de cero para todas las llamadas posteriores.

En el ejemplo también se usa la CountdownEvent clase para asegurarse de que cada subproceso ha terminado de generar números aleatorios antes de mostrar el número total de llamadas. De lo contrario, si el subproceso principal completa la ejecución antes de los subprocesos adicionales que genera, muestra un valor inexacto para el número total de llamadas al método.

Comentarios

Un static campo marcado con ThreadStaticAttribute no se comparte entre subprocesos. Cada subproceso en ejecución tiene una instancia independiente del campo, y establece y obtiene valores para ese campo de forma independiente. Si se tiene acceso al campo en un subproceso diferente, contendrá un valor diferente.

Tenga en cuenta que además de aplicar el ThreadStaticAttribute atributo a un campo, también debe definirlo como un static campo (en C# o F#) o un Shared campo (en Visual Basic).

Nota

No especifique valores iniciales para los campos marcados con ThreadStaticAttribute, ya que dicha inicialización solo se produce una vez, cuando se ejecuta el constructor de clase y, por lo tanto, solo afecta a un subproceso. Si no especifica un valor inicial, puede confiar en el campo que se inicializa en su valor predeterminado si es un tipo de valor o si null es un tipo de referencia.

Use este atributo tal cual y no derive de él.

Para obtener más información sobre el uso de atributos, vea Atributos.

Constructores

ThreadStaticAttribute()

Inicializa una nueva instancia de la clase ThreadStaticAttribute.

Propiedades

TypeId

Cuando se implementa en una clase derivada, obtiene un identificador único para este Attribute.

(Heredado de Attribute)

Métodos

Equals(Object)

Devuelve un valor que indica si esta instancia es igual que un objeto especificado.

(Heredado de Attribute)
GetHashCode()

Devuelve el código hash de esta instancia.

(Heredado de Attribute)
GetType()

Obtiene el Type de la instancia actual.

(Heredado de Object)
IsDefaultAttribute()

Si se reemplaza en una clase derivada, indica si el valor de esta instancia es el valor predeterminado de la clase derivada.

(Heredado de Attribute)
Match(Object)

Cuando se invalida en una clase derivada, devuelve un valor que indica si esta instancia es igual a un objeto especificado.

(Heredado de Attribute)
MemberwiseClone()

Crea una copia superficial del Object actual.

(Heredado de Object)
ToString()

Devuelve una cadena que representa el objeto actual.

(Heredado de Object)

Implementaciones de interfaz explícitas

_Attribute.GetIDsOfNames(Guid, IntPtr, UInt32, UInt32, IntPtr)

Asigna un conjunto de nombres a un conjunto correspondiente de identificadores de envío.

(Heredado de Attribute)
_Attribute.GetTypeInfo(UInt32, UInt32, IntPtr)

Obtiene la información de tipos de un objeto, que puede utilizarse para obtener la información de tipos de una interfaz.

(Heredado de Attribute)
_Attribute.GetTypeInfoCount(UInt32)

Recupera el número de interfaces de información de tipo que proporciona un objeto (0 ó 1).

(Heredado de Attribute)
_Attribute.Invoke(UInt32, Guid, UInt32, Int16, IntPtr, IntPtr, IntPtr, IntPtr)

Proporciona acceso a las propiedades y los métodos expuestos por un objeto.

(Heredado de Attribute)

Se aplica a

Consulte también