web-dev-qa-db-ja.com

ThreadStatic v.s. ThreadLocal <T>:属性よりも一般的ですか?

[ThreadStatic]は属性を使用して定義され、ThreadLocal<T>はジェネリックを使用します。なぜ異なる設計ソリューションが選ばれたのですか?この場合、属性よりもジェネリックを使用する利点と欠点は何ですか?

83
user2341923

コメントで記されたブログ投稿では明示されていませんが、[ThreadStatic]はすべてのスレッドに対して自動的に初期化するわけではないということが非常に重要だと思います。たとえば、これがあるとします:

[ThreadStatic]
private static int Foo = 42;

これを使用する最初のスレッドでは、Foo42に初期化されます。ただし、後続のスレッドはそうではありません。初期化子は、最初のスレッドに対してのみ機能します。そのため、初期化されているかどうかを確認するコードを記述する必要があります。

ThreadLocal<T>は、アイテムに最初にアクセスする前に実行される初期化関数(Reedのブログが示すように)を提供できるようにすることで、この問題を解決します。

私の意見では、[ThreadStatic]の代わりにThreadLocal<T>を使用する利点はありません。

94
Jim Mischel

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();
    }

enter image description here

33
marai

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の個別のコピーがあります。

enter image description here

そのため、ThreadStatic変数は、それが作成されたスレッドを除く他のスレッドでデフォルト値に初期化されます。

独自の方法で各スレッドの変数を初期化する場合は、ThreadLocalを使用します。

11
user2463026