ThreadStaticAttribute 클래스
정의
중요
일부 정보는 릴리스되기 전에 상당 부분 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적이거나 묵시적인 보증도 하지 않습니다.
정적 필드의 값이 각 스레드에 대해 고유함을 나타냅니다.
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
- 상속
- 특성
예제
다음 예제에서는 난수 생성기를 인스턴스화하고, 주 스레드 외에도 10개의 스레드를 만든 다음, 각 스레드에서 2백만 개의 난수를 생성합니다. 특성을 사용하여 ThreadStaticAttribute 스레드당 난수의 합계와 수를 계산합니다. 또한 스레드당 두 개의 추가 필드를 정의하며abnormal
, previous
이를 통해 난수 생성기의 손상을 감지할 수 있습니다.
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.
이 예제에서는 C#의 lock
문, F#의 lock
함수 및 SyncLock
Visual Basic 구문을 사용하여 난수 생성기에 대한 액세스를 동기화합니다. 이렇게 하면 난수 생성기가 손상되는 것을 방지할 수 있으며, 이로 인해 일반적으로 모든 후속 호출에 대해 값이 0으로 반환됩니다.
또한 이 예제에서는 클래스를 CountdownEvent 사용하여 각 스레드가 총 호출 수를 표시하기 전에 난수 생성을 완료했는지 확인합니다. 그렇지 않으면 기본 스레드가 생성되는 추가 스레드 전에 실행을 완료하면 메서드 호출의 총 수에 대한 부정확한 값이 표시됩니다.
설명
static
표시된 ThreadStaticAttribute 필드는 스레드 간에 공유되지 않습니다. 실행 중인 각 스레드에는 별도의 필드 인스턴스가 있으며 해당 필드에 대한 값을 독립적으로 설정하고 가져옵니다. 필드가 다른 스레드에서 액세스되면 다른 값이 포함됩니다.
필드에 특성을 적용하는 ThreadStaticAttribute 것 외에도 필드(C# 또는 F#) 또는 Shared
필드(Visual Basic)로 static
정의해야 합니다.
참고
이러한 초기화는 클래스 생성자가 실행되면 한 번만 발생하므로 하나의 스레드에만 영향을 주므로 표시된 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) |