【问题标题】:Thread Local Storage For C# Class LibraryC# 类库的线程本地存储
【发布时间】:2011-12-12 15:31:05
【问题描述】:

我有一个非常旧但非常大的库,我正在考虑将其转换为 C# 类库。现有库使用大量存储在 TLS 中的全局变量。 C# 没有全局变量的真正概念,但一种解决方法是使用名为 GlobalVar 之类的静态类并将它们全部放在此类中,以便可以通过 GlobalVar.xxxxxx 访问它们

但是,我的想法是,这将破坏所有正在转换的现有代码,因为 GlobalVar 类将是一个普通的全局类,而不是每个线程存储。有没有办法让这些全局变量成为每个线程?即 C# 中 __declspec (thread) static 的等价物是什么?

此时我应该补充一点,我讨厌全局变量。我认为它们通常是糟糕设计的结果。但是,由于时间紧迫,第一阶段是将库转换为 C# 以最小的麻烦,然后第二阶段将重新设计它们。

【问题讨论】:

    标签: c# multithreading global-variables


    【解决方案1】:

    允许线程以独占方式访问自己的线程不安全版本有三种主要方法 对象。

    1- [线程静态] 实现非常简单,可以通过使用[ThreadStatic] 属性签署静态字段来完成

    [ThreadStatic] static int y;
    

    现在每个线程都会看到一个单独的 y 副本; 不幸的是,[ThreadStatic] 不适用于实例字段。

    2- 线程本地 它是framework 4.0 的新功能,它为静态和实例字段提供线程本地存储。 此外,您可以为每个线程提供默认值,并延迟评估该值。

    static ThreadLocal<int> y = new ThreadLocal<int> (() => 10);  //Static variable
    ThreadLocal<int> y = new ThreadLocal<int> (() => 10);  //Instance variable
    

    3- GetData 和 SetData 在这种方法中,Thread 类的两个方法正在使用:GetDataSetData。 这些方法将数据存储在线程特定的“插槽”中。应指定名称 槽,因此可以在所有线程中使用相同的槽,它们将获得单独的值。

     // The same LocalDataStoreSlot object can be used across all threads.
       LocalDataStoreSlot y= Thread.GetNamedDataSlot ("slotName");
       object data = Thread.GetData (y);
       Thread.SetData (y, value)
    

    【讨论】:

      【解决方案2】:

      ThreadLocal 类(4.0 中引入)和ThreadStaticAttribute

      ThreadStaticAttribute 只能用于static 字段。 ThreadLocal 类可用于“普通”字段,但速度较慢。

      请注意,如果您不控制您所在的线程(例如,您是 ASP.NET 的页面,并且您从“随机”预用线程开始,或者您是 ThreadPool 的线程) ,那么您的“线程静态”(通常不是属性)变量将使用前一个线程的旧值进行预初始化。 (例如参见A tale of two techniques: The [ThreadStatic] Attribute and System.Web.HttpContext.Current.Items

      我忘记了,Thread.AllocateDataSlot 的“目标”与其他人相似。

      【讨论】:

      • 呵呵,你好像坚持要教我们意大利语:-)
      • @xanatos The ThreadStaticAttribute can be used only on static fields 并不总是正确的。人们可能想要声明一个每个线程每个实例的变量
      • 我的意大利语不是那么好,只是开玩笑,非常感谢您的帮助。虽然我有点担心最后一段与使用线程池有关。我不认为这将是一个问题,但它是未来可能需要考虑的问题。
      • @UweKeim 我感到羞愧 :-( 有趣的是我总是阅读英文版的 MSDN 页面 :-) :-) 但是 MSDN 喜欢给我看意大利版(此时我已将其设置为向我显示页面的原始版本,但它仍将我重定向到带有英文文本的 it-it 页面)
      • @UweKeim 你有没有看到我的其他指向 it-it 资源的链接?
      【解决方案3】:

      假设您要使用 .NET 4.0,您可以有一个 static ThreadLocal&lt;ThreadLocalData&gt;,其中您的 ThreadLocalData 类将所有变量作为属性:

      class ThreadLocalData
      {
          public int GlobalInt { get; set; }
          public string GlobalString { get; set; }
      }
      
      class Global
      {
          static ThreadLocal<ThreadLocalData> _ThreadLocal =
              new ThreadLocal<ThreadLocalData>( () => new ThreadLocalData() );
      
          public static ThreadLocalData ThreadLocal
          {
             get { return _ThreadLocal.Value; }
          }
      }
      

      然后您可以像这样访问属性:

      int i = Global.ThreadLocal.GlobalInt;
      

      您可以添加任何非线程局部的全局变量作为Global 类的普通属性。

      【讨论】:

        【解决方案4】:

        您可以使用[ThreadStatic] 属性或在.Net 4 中使用ThreadLocal 类来实现相同的线程本地存储。

        [ThreadStatic]    
        private static string MyThreadGlobal;
        
        private ThreadLocal<string> MyThreadGlobal = new ThreadLocal<string>();
        

        还有 CallContext 类,但其他方法可能是首选。

        【讨论】:

          猜你喜欢
          • 2011-01-04
          • 2020-08-09
          • 2014-06-01
          • 1970-01-01
          • 2023-04-08
          • 1970-01-01
          • 1970-01-01
          • 2010-11-27
          相关资源
          最近更新 更多