[ThreadStatic]
は属性を使用して定義され、ThreadLocal<T>
はジェネリックを使用します。なぜ異なる設計ソリューションが選ばれたのですか?この場合、属性よりもジェネリックを使用する利点と欠点は何ですか?
コメントで記されたブログ投稿では明示されていませんが、[ThreadStatic]
はすべてのスレッドに対して自動的に初期化するわけではないということが非常に重要だと思います。たとえば、これがあるとします:
[ThreadStatic]
private static int Foo = 42;
これを使用する最初のスレッドでは、Foo
が42
に初期化されます。ただし、後続のスレッドはそうではありません。初期化子は、最初のスレッドに対してのみ機能します。そのため、初期化されているかどうかを確認するコードを記述する必要があります。
ThreadLocal<T>
は、アイテムに最初にアクセスする前に実行される初期化関数(Reedのブログが示すように)を提供できるようにすることで、この問題を解決します。
私の意見では、[ThreadStatic]
の代わりにThreadLocal<T>
を使用する利点はありません。
ThreadStaticは、最初のスレッドでのみ初期化し、各スレッドでThreadLocalを初期化します。以下は簡単なデモです。
public static ThreadLocal<int> _threadlocal =
new ThreadLocal<int>(() =>
{
return Thread.CurrentThread.ManagedThreadId;
});
public static void Main()
{
new Thread(() =>
{
for (int x = 0; x < _threadlocal.Value; x++)
{
Console.WriteLine("First Thread: {0}", x);
}
}).Start();
new Thread(() =>
{
for (int x = 0; x < _threadlocal.Value; x++)
{
Console.WriteLine("Second Thread: {0}", x);
}
}).Start();
Console.ReadKey();
}
ThreadStaticの背後にある主なアイデアは、変数のseparate copyを維持することです各スレッドに対して。
class Program
{
[ThreadStatic]
static int value = 10;
static void Main(string[] args)
{
value = 25;
Task t1 = Task.Run(() =>
{
value++;
Console.WriteLine("T1: " + value);
});
Task t2 = Task.Run(() =>
{
value++;
Console.WriteLine("T2: " + value);
});
Task t3 = Task.Run(() =>
{
value++;
Console.WriteLine("T3: " + value);
});
Console.WriteLine("Main Thread : " + value);
Task.WaitAll(t1, t2, t3);
Console.ReadKey();
}
}
上記のスニペットでは、メインスレッドを含む各スレッドにvalue
の個別のコピーがあります。
そのため、ThreadStatic変数は、それが作成されたスレッドを除く他のスレッドでデフォルト値に初期化されます。
独自の方法で各スレッドの変数を初期化する場合は、ThreadLocalを使用します。