ThreadStatic与ThreadLocal <T>:比属性更通用吗?

use*_*923 85 c# generics attributes thread-local threadstatic

[ThreadStatic]ThreadLocal<T>使用泛型时使用属性定义.为什么选择不同的设计方案?在这种情况下使用泛型over属性有哪些优缺点?

Jim*_*hel 96

博客文章在评论中提到的东西没有明确,但我觉得非常重要,那就是[ThreadStatic]不会自动为每个线程初始化事物.例如,假设你有这个:

[ThreadStatic]
private static int Foo = 42;
Run Code Online (Sandbox Code Playgroud)

使用它的第一个线程将看到Foo初始化为42.但随后的线程不会.初始化程序仅适用于第一个线程.因此,您最终必须编写代码来检查它是否已初始化.

ThreadLocal<T> 通过让您提供在第一次访问项目之前运行的初始化函数(如Reed的博客显示)来解决该问题.

在我看来,使用[ThreadStatic]而不是使用ThreadLocal<T>.

  • 除了可能在.NET 4及更高版本中提供[`ThreadLocal <T>`](http://msdn.microsoft.com/en-us/library/dd642243(v = vs.110).aspx),[ "ThreadStatic"属性(http://msdn.microsoft.com/en-us/library/system.threadstaticattribute(v = vs.100).aspx)也可在3.5及以下版本中使用. (18认同)
  • 除了`ThreadLocal <T>`实现`IDisposable`并且通常强制你实现`IDisposable`,这迫使你的调用者处理你,因此也实现`IDisposable` ... (9认同)
  • @StefanSteinegger:我会非常小心地使用带有池线程的`ThreadLocal`或`ThreadStatic`.这些值将保留在池线程的整个生命周期中,而不仅仅是您分配它的任务.这可能会以一些非常明显的方式给你带来麻烦.有关详细信息,请参阅http://stackoverflow.com/questions/561518/is-thread-local-storage-persisted-between-backgroundworker-invocations和类似问题. (4认同)
  • 不应该将示例中的字段声明为"static"吗?请参阅https://msdn.microsoft.com/en-us/library/system.threadstaticattribute(v=vs.110).aspx (3认同)
  • 而且,如果您不使用初始化程序来设置值,而是在初始化后的某个晚些时候对其进行设置,则使用[ThreadStatic]在语法上更干净。 (2认同)
  • ThreadLocal&lt;&gt; 与 ThreadStatic 相比似乎稍微慢一些。 (2认同)
  • 如果您查看 ThreadLocal (https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Threading/ThreadLocal.cs) 的实现,您会看到它在幕后使用 ThreadStatic。这是一个天真的基准 https://pastebin.com/Ym55kZi9 (2认同)

mar*_*rai 34

ThreadStatic仅在第一个线程初始化,每个线程的ThreadLocal Initialize.以下是简单演示:

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

在此输入图像描述


use*_*026 13

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

在上面的代码片段中,我们value为每个线程提供了一个单独的副本,包括主线程.

在此输入图像描述

因此,ThreadStatic变量将在其他线程上初始化为其默认值,但创建它的线程除外.

如果我们想以自己的方式在每个线程上初始化变量,请使用ThreadLocal.

  • 完整的文章可以在这里找到(http://putridparrot.com/blog/using-threadstatic-and-threadlocal/)。 (2认同)