C#类库的线程本地存储

时间:2011-10-21 14:26:33

标签: c# multithreading global-variables

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

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

我应该补充一点,我讨厌全局变量。我认为它们往往是设计不佳的结果。但是,由于严格的时间限制,第一阶段是将库转换为C#,而不是大惊小怪,然后第二阶段将重新设计它们。

4 个答案:

答案 0 :(得分:14)

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的“目标”与其他目标相似。

答案 1 :(得分:4)

假设你要使用.NET 4.0,你可以static ThreadLocal<ThreadLocalData>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类的常规属性。

答案 2 :(得分:3)

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

[ThreadStatic]    
private static string MyThreadGlobal;

private ThreadLocal<string> MyThreadGlobal = new ThreadLocal<string>();

还有CallContext类,但其他方法可能更受欢迎。

答案 3 :(得分:0)

有三种主要方法允许线程专有地访问其自身版本的线程不安全 对象。

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

[ThreadStatic] static int y;

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

2- ThreadLocal 它是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)