ThreadStaticAttribute Класс
Определение
Важно!
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Указывает, что значение статического поля уникально для каждого потока.
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
- Наследование
- Атрибуты
Примеры
В следующем примере создается генератор случайных чисел, создается десять потоков в дополнение к основному потоку, а затем создается два миллиона случайных чисел в каждом потоке. Он использует ThreadStaticAttribute атрибут для вычисления суммы и количества случайных чисел на поток. Он также определяет два дополнительных поля для каждого потока и previous
abnormal
позволяет обнаруживать повреждение генератора случайных чисел.
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.
В примере используется lock
инструкция в C#, lock
функция в F#, а SyncLock
также конструкция в Visual Basic для синхронизации доступа к генератору случайных чисел. Это предотвращает повреждение генератора случайных чисел, что обычно приводит к возвращению нулевых значений для всех последующих вызовов.
В примере также используется CountdownEvent класс, чтобы убедиться, что каждый поток завершил создание случайных чисел перед отображением общего числа вызовов. В противном случае, если основной поток завершает выполнение до дополнительных потоков, которые он создает, отображается неточное значение для общего числа вызовов методов.
Комментарии
Поле, помеченное static
как ThreadStaticAttribute не совместное использование между потоками. Каждый выполняемый поток имеет отдельный экземпляр поля, а также независимо задает и получает значения для этого поля. Если доступ к полю осуществляется в другом потоке, он будет содержать другое значение.
Обратите внимание, что помимо применения атрибута ThreadStaticAttribute к полю необходимо также определить его как static
поле (в C# или F#) или Shared
поле (в Visual Basic).
Примечание
Не указывайте начальные значения для полей, помеченных как ThreadStaticAttribute
один раз, так как такая инициализация происходит только один раз, когда конструктор класса выполняется и, следовательно, влияет только на один поток. Если не указать начальное значение, можно использовать поле, инициализируемого в его значение по умолчанию, если это тип значения, или ссылочного null
типа.
Используйте этот атрибут как есть и не наследуйте его.
Дополнительные сведения об использовании атрибутов см. в разделе "Атрибуты".
Конструкторы
ThreadStaticAttribute() |
Инициализирует новый экземпляр класса ThreadStaticAttribute. |
Свойства
TypeId |
В случае реализации в производном классе возвращает уникальный идентификатор для этого атрибута Attribute. (Унаследовано от Attribute) |
Методы
Equals(Object) |
Возвращает значение, показывающее, равен ли экземпляр указанному объекту. (Унаследовано от Attribute) |
GetHashCode() |
Возвращает хэш-код данного экземпляра. (Унаследовано от Attribute) |
GetType() |
Возвращает объект Type для текущего экземпляра. (Унаследовано от Object) |
IsDefaultAttribute() |
При переопределении в производном классе указывает, является ли значение этого экземпляра значением по умолчанию для производного класса. (Унаследовано от Attribute) |
Match(Object) |
При переопределении в производном классе возвращает значение, указывающее, является ли этот экземпляр равным заданному объекту. (Унаследовано от Attribute) |
MemberwiseClone() |
Создает неполную копию текущего объекта Object. (Унаследовано от Object) |
ToString() |
Возвращает строку, представляющую текущий объект. (Унаследовано от Object) |
Явные реализации интерфейса
_Attribute.GetIDsOfNames(Guid, IntPtr, UInt32, UInt32, IntPtr) |
Сопоставляет набор имен соответствующему набору идентификаторов диспетчеризации. (Унаследовано от Attribute) |
_Attribute.GetTypeInfo(UInt32, UInt32, IntPtr) |
Возвращает сведения о типе объекта, которые можно использовать для получения сведений о типе интерфейса. (Унаследовано от Attribute) |
_Attribute.GetTypeInfoCount(UInt32) |
Возвращает количество предоставляемых объектом интерфейсов для доступа к сведениям о типе (0 или 1). (Унаследовано от Attribute) |
_Attribute.Invoke(UInt32, Guid, UInt32, Int16, IntPtr, IntPtr, IntPtr, IntPtr) |
Предоставляет доступ к открытым свойствам и методам объекта. (Унаследовано от Attribute) |