ThreadStatic属性はどのように機能しますか?


138

[ThreadStatic]属性はどのように機能しますか?コンパイラーがILを放出してTLSに値を入れたり取得したりすると想定しましたが、逆アセンブリを見ると、そのレベルではそうではないようです。

フォローアップとして、それを非静的メンバーに配置するとどうなりますか?私たちは開発者にその間違いを犯させ、コンパイラは警告を提供しません。

更新

2番目の質問がここで回答:静的C#で変更されたThreadStatic


1
生成されたILが同じである場合(実際には同じ)、そのような装飾されたフィールドにヒットしたときに値を割り当てて読み取る方法を知るために、ランタイムを具体的にコード化する必要があります。ハックのようです:)
レックスM

回答:


92

静的スレッドの実装セマンティクスは、.NET jitコンパイラーでは、ILレベル未満です。VB.NETやC#のようにILに出力するコンパイラーは、ThreadStatic属性を持つ変数を読み書きできるILコードを出力するために、Win32 TLSについて何も知る必要はありません。C#が知る限り、変数について特別なことは何もありません。これは、データを読み書きするための場所にすぎません。それがそれに属性を持っているという事実はC#に影響を与えません。C#は、そのシンボル名のIL読み取りまたは書き込み命令を発行することを知る必要があるだけです。

「重いリフティング」は、特定のハードウェアアーキテクチャでILを機能させるコアCLRによって実行されます。

これは、不適切な(静的でない)シンボルに属性を設定してもコンパイラーからの反応が得られない理由も説明します。コンパイラーは、属性が必要とする特別なセマンティクスを知りません。ただし、FX / Copなどのコード分析ツールはそれについて知っている必要があります。

別の見方:CILは一連のストレージスコープを定義します:静的(グローバル)ストレージ、メンバーストレージ、スタックストレージ。TLSがリストに含まれている必要はないため、TLSはリストに含まれていません。シンボルがTLS属性でタグ付けされているときに、ILの読み取りおよび書き込み命令でTLSにアクセスできる場合、ILにTLSの特別な表現または処理が必要なのはなぜですか?必要ありません。


しかし、TLSの特別な実装固有の動作は、.NET / CLRの「検証可能な」セールスポイントを完全に覆しませんか?

116

[ThreadStatic]属性はどのように機能しますか?

あなたはThreadStaticでマークされたフィールドと考えることができますでスレッドにアタッチされ、その存続期間はスレッドの存続期間に匹敵する。

したがって、疑似コードでThreadStaticは(セマンティクスにより)スレッドにキー値をアタッチするのと似ています。

Thread.Current["MyClass.myVariable"] = 1;
Thread.Current["MyClass.myvariable"] += 1;

しかし、構文は少し簡単です:

class MyClass {
  [ThreadStatic]
  static int myVariable;
}
// .. then
MyClass.myVariable = 1;
MyClass.myVariable += 1;

非静的メンバーに配置するとどうなりますか?

私はそれが無視されていると思います:

    class A {
        [ThreadStatic]
        public int a;
    }
    [Test]
    public void Try() {
        var a1 = new A();
        var a2 = new A();
        a1.a = 5;
        a2.a = 10;
        a1.a.Should().Be.EqualTo(5);
        a2.a.Should().Be.EqualTo(10);
    }

さらにThreadStatic、通常の静的フィールドと比較して、同期メカニズムを必要としないことにも言及する価値があります(状態が共有されないため)。


1
擬似コードの2番目の例はで"MyClass.myVariable"ある必要がありますね。
akshay2000 2016

正確な制限はわかりませんが、プリミティブ型である必要がないことが明らかでない場合は指摘したいと思います。以下のためにあなたは、ソースを見ればTransactionScope、彼らはスコープ(のためにそこにもののすべての種類を格納しreferencesource.microsoft.com/#System.Transactions/System/...
Simon_Weaver

10

[ThreadStatic]は、各スレッドで同じ変数の分離バージョンを作成します。

例:

[ThreadStatic] public static int i; // Declaration of the variable i with ThreadStatic Attribute.

public static void Main()
{
    new Thread(() =>
    {
        for (int x = 0; x < 10; x++)
        {
            i++;
            Console.WriteLine("Thread A: {0}", i); // Uses one instance of the i variable.
        }
    }).Start();

    new Thread(() =>
   {
       for (int x = 0; x < 10; x++)
       {
           i++;
           Console.WriteLine("Thread B: {0}", i); // Uses another instance of the i variable.
       }
   }).Start();
}

3

でマークされたフィールド [ThreadStatic]されたスレッドローカルストレージに作成されるため、すべてのスレッドはフィールドの独自のコピーを持っています。つまり、フィールドのスコープはスレッドに対してローカルです。

TLSフィールドは、gs / fsセグメントレジスタを介してアクセスします。これらのセグメントは、OSカーネルがスレッド固有のメモリにアクセスするために使用されます。.netコンパイラはILを発行せず、TLSの値をスタッフ/取得しません。これはOSカーネルによって行われます。

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