【问题标题】:ThreadStatic v.s. ThreadLocal<T>: is generic better than attribute?ThreadStatic 与 ThreadStatic 对比ThreadLocal<T>:泛型比属性好吗?
【发布时间】:2013-08-22 10:27:01
【问题描述】:

[ThreadStatic] 使用属性定义,而ThreadLocal&lt;T&gt; 使用泛型。 为什么选择不同的设计解决方案? 在这种情况下使用泛型优于属性有什么优缺点?

【问题讨论】:

标签: c# generics attributes thread-local threadstatic


【解决方案1】:

在 cmets 中提到的博客文章没有明确说明,但我发现非常重要的是,[ThreadStatic] 不会自动为每个线程初始化事物。例如,假设你有这个:

[ThreadStatic]
private static int Foo = 42;

使用它的第一个线程将看到Foo 初始化为42。但后续线程不会。初始化程序仅适用于第一个线程。所以你最终不得不编写代码来检查它是否已初始化。

ThreadLocal&lt;T&gt; 通过让您提供一个在第一次访问项目之前运行的初始化函数(如 Reed 的博客所示)解决了这个问题。

在我看来,使用[ThreadStatic] 代替ThreadLocal&lt;T&gt; 没有任何优势。

【讨论】:

  • 除了ThreadLocal&lt;T&gt; 可能在 .NET 4 及更高版本中可用,the ThreadStatic attribute 在 3.5 及更低版本中也可用。
  • 如果你不使用初始化器来设置值,而是在初始化后的某个时间点设置它,使用 [ThreadStatic] 在语法上更简洁。
  • 除了 ThreadLocal&lt;T&gt; 实现 IDisposable 并且通常强制您实现 IDisposable 之外,这会迫使您的调用者处置您,因此也实现 IDisposable ...跨度>
  • @StefanSteinegger:我会非常小心地将ThreadLocalThreadStatic 与池线程一起使用。这些值将在池线程的整个生命周期中保留,而不仅仅是您分配的任务。这可能会以一些非常不明显的方式给你带来麻烦。有关详细信息,请参阅 stackoverflow.com/questions/561518/… 和类似问题。
  • 示例中的字段不应该也声明为static吗?见msdn.microsoft.com/en-us/library/…
【解决方案2】:

ThreadStatic 仅在第一个线程上初始化,ThreadLocal 对每个线程进行初始化。下面是简单的演示:

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

【讨论】:

    【解决方案3】:

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

    在上面的 sn-p 中,我们为每个线程(包括主线程)提供了一个单独的 value 副本。

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

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

    【讨论】:

    • 完整文章可以在here找到。
    猜你喜欢
    • 2016-08-28
    • 1970-01-01
    • 2020-11-10
    • 2014-08-30
    • 1970-01-01
    • 2016-10-30
    • 2010-09-21
    • 2016-03-02
    相关资源
    最近更新 更多