150

[ThreadStatic]属性はどのように機能しますか?コンパイラーがTLSの値を詰め込んだり取得したりするためにILを発行すると想定しましたが、分解を見ると、そのレベルでは実行されていないようです。

フォローアップとして、非静的メンバーに配置するとどうなりますか?開発者にその間違いを犯してもらいましたが、コンパイラーは警告さえ出さないのです。

アップデート

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

4

4 に答える 4

123

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

于 2011-03-08T02:48:27.360 に答える
100

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

「重労働」は、特定のハードウェアアーキテクチャでILを機能させる役割を担うコアCLRによって実行されます。

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

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

于 2011-03-08T02:51:48.410 に答える
17

[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();
}
于 2018-04-19T13:18:49.033 に答える
9

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

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

于 2019-10-21T19:06:05.090 に答える