ThreadStaticとThreadLocal <T>:属性よりも一般的な方が優れていますか?


94

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


4
reedcopsey.com/2009/11/12/を参照してください...-これがリフレクションとどう関係しているのかわかりません...
Jon Skeet

回答:


111

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

[ThreadStatic]
private static int Foo = 42;

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

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

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


20
おそらくそれThreadLocal<T>は.NET 4以降で利用可能でありThreadStatic属性は3.5以下でも利用可能です。
Jeroen 2014

2
また、値を設定するためにイニシャライザを使用せずに、初期化後のある時点で値を設定する場合は、[ThreadStatic]を使用すると構文的にクリーンになります。
考えた

9
そして、それをThreadLocal<T>実装しIDisposable、通常は実装IDisposableも強制します。これにより、呼び出し元があなたを処分し、したがって実装IDisposable
強制

4
@StefanSteinegger:私は、プールスレッドの使用ThreadLocalまたは使用に非常に注意ThreadStaticします。これらの値は、割り当てたタスクだけでなく、プールスレッドの存続期間全体にわたって残ります。それはあなたにいくつかのかなり非自明な方法で問題を引き起こす可能性があります。詳細については、stackoverflow.com / questions / 561518 / および同様の質問をご覧ください。
ジムミッシェル、2015

3
例のフィールドも宣言する必要はありませんstaticか?msdn.microsoft.com/en-us/library/…を
entheh

39

ThreadStatic Initialize on first thread、ThreadLocal Initialize for each thread。以下は簡単なデモです:

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

ここに画像の説明を入力してください


14

ThreadStaticの主な目的は、スレッドごとに変数の個別のコピーを維持することです。

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を使用します。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.