ThreadStatic属性如何工作?

jos*_*rry 134 c# static threadstatic

[ThreadStatic]属性如何工作?我假设编译器会发出一些IL来填充/检索TLS中的值,但是看一下反汇编它似乎不会在那个级别上执行.

作为跟进,如果你把它放在非静态成员身上会发生什么?我们有一个开发人员犯了这个错误,编译器甚至没有提出警告.

更新

第二个问题在这里回答:使用Static C#修改ThreadStatic

Dmy*_*iak 111

[ThreadStatic]属性如何工作?

您可以认为标记为ThreadStatic的字段附加到线程,其生命周期与线程的生命周期相当.

所以在伪代码ThreadStatic中(通过语义)类似于将一个键值附加到一个线程:

Thread.Current["MyClass.myVariable"] = 1;
Thread.Current["MyClass.myvariable"] += 1;
Run Code Online (Sandbox Code Playgroud)

但语法更简单:

class MyClass {
  [ThreadStatic]
  static int myVariable;
}
// .. then
MyClass.myVariable = 1;
MyClass.myVariable += 1;
Run Code Online (Sandbox Code Playgroud)

如果你把它放在非静态成员身上会发生什么?

我相信它被忽略了:

    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);
    }
Run Code Online (Sandbox Code Playgroud)

另外值得一提的是ThreadStatic,与普通静态字段相比,不需要任何同步机制(因为状态不是共享的).


dth*_*rpe 89

在.NET jit编译器中,线程静态的实现语义低于IL级别.像VB.NET和C#一样向IL发出的编译器不需要知道任何关于Win32 TLS的内容,以便发出可以读取和写入具有ThreadStatic属性的变量的IL代码.就C#而言,变量并没有什么特别之处 - 它只是一个读写东西的位置.它具有属性的事实对C#没有任何影响.C#只需要知道为该符号名称发出IL读或写指令.

"繁重的工作"由核心CLR完成,它负责使IL在特定的硬件架构上工作.

这也可以解释为什么将属性放在不合适的(非静态)符号上不会得到编译器的反应.编译器不知道属性需要什么特殊语义.但是,像FX/Cop这样的代码分析工具应该知道它.

另一种查看方式:CIL定义了一组存储范围:静态(全局)存储,成员存储和堆栈存储.TLS不在该列表中,很可能因为TLS不需要在该列表上.如果IL读取和写入指令足以在使用TLS属性标记符号时访问TLS,为什么IL对TLS有任何特殊表示或处理?这不是必需的.


Ari*_*gri 8

标记为 的字段[ThreadStatic]是在线程本地存储上创建的,因此每个线程都有自己的字段副本,即字段的范围是线程本地的。

TLS 字段通过 gs/fs 段寄存器访问。操作系统内核使用这些段来访问线程特定的内存。.net 编译器不会发出任何 IL 来填充/检索 TLS 中的值。它是由操作系统内核完成的。


小智 7

[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();
}
Run Code Online (Sandbox Code Playgroud)