【C# 线程】数据槽 LocalDataStoreSlot简称DataSlot

背景

为了确保在线程中声明特定类型的变量,在每个线程中的值都是唯一的,不受到其他线程对该变量读写的影响。也就是俗称的线程本地存储 (TLS),可用于存储对线程和应用程序域唯一的数据。

例如:主线程中声明了变量A ,只能由主线程进行读取和写入。子线程虽然可以使用变量A(相当于复制一个A,可以对该变量进行读写),却无法读取和写入主线变量中A的值。

.net提供了3种方式:

1、线程相对静态字段 相对于线程的静态字段(ThreadStaticAttribute)

2、数据槽  LocalDataStoreSlot

3、ThreadLocal<T>

托管线程本地存储 (TLS) 可用于存储对线程和应用程序域唯一的数据。 .NET 提供了下面两种托管 TLS 使用方式:线程相对静态字段和数据槽。

数据槽 LocalDataStoreSlot简称DataSlot

背景:为了解决多线程竞用共享资源的问题,引入数据槽的概念,即将数据存放到线程的环境块中,使该数据只能单一线程访问.(属于线程空间上的开销)

 

 

 

 

 

 Thread 静态类的内部有一个静态类LocalDataStore。该类维护这一个静态字典,该字典装着所有线程的LocalDataStoreSlot的变量。LocalDataStoreSlot类是ThreadLocal<object> Data封装。

 

  ①:AllocateNamedDataSlot命名槽位和AllocateDataSlot未命名槽位 解决线程竞用资源共享问题。

 

数据槽对于每个线程都是唯一的。 没有其他线程 (甚至子线程) 可以获取该数据。

.NET 提供了对于线程和应用程序域都是唯一的动态数据槽。 数据槽分为下列两种类型:命名槽和未命名槽。 两种类型都是使用 LocalDataStoreSlot 结构实现。LocalDataStoreSlot 封装的是internal ThreadLocal<object> Data 字段。

对于命名槽和未命名槽,请使用 Thread.SetDataThread.GetData 方法设置和检索槽中的信息。 这些静态方法始终处理当前正在执行它们的线程的数据。

命名槽非常便捷,因为可以在需要时检索槽,具体操作是将它的名称传递给 GetNamedDataSlot 方法,而不用维护对未命名槽的引用。 不过,如果另一个组件对线程相对存储使用相同的名称,并且线程同时执行你的组件和另一个组件的代码,这两个组件可能会相互损坏数据。 (此方案假定这两个组件都在同一个应用域中运行,并不旨在共享相同的数据。)

 

显然ThreadStatic特性只支持静态字段太受限制了,.NET线程类型中的LocalDataStoreSlot提供更好的TLS支持,但是性能不如上面介绍的ThreadStatic方法。注意:LocalDataStoreSlot有命名类型和非命名类型区分。

我们先来看看命名的LocalDataStoreSlot类型,可以通过Thread.AllocateNamedDataSlot来分配一个的空间,通过Thread.FreeNamedDataSlot来销毁一个的空间。

把线程相关的数据存储在LocalDataStoreSlot对象中,数据槽的获取和设置则通过Thread类型的GetData方法和SetData方法。

存放局部存储步骤:
1、申请数据槽

= Thread.GetNamedDataSlot("para");


如果不存在名为para的数据槽,将分配一个所有线程均可用的para数据槽
2、往数据槽存放数据

= new MyPara();
para.I = i;
Thread.SetData(slot,para);


3、如有必要,释放数据槽

Thread.FreeNamedDataSlot("para");


释放数据槽要小心,该操作将使所有线程存放在被释放的数据槽中的数据丢失。

读取局部存储步骤:
1、根据名字子线程局部存储中获取特定的数据槽

= Thread.GetNamedDataSlot("para");

2、从数据槽获取数据

= Thread.GetData(slot);
if (o != null)
{
 //转化为特定类型
 MyPara para = (MyPara) o ;
 //.
}
复制代码
 
class Programe
{


   // [ThreadStatic] public static string Username = "";
    static void Main()
    {
        LocalDataStoreSlot Username = Thread.AllocateNamedDataSlot("userName");
        Thread.SetData(Username, "mainthread");
        Thread thread1 = new Thread(() => { 
//Username = Thread.AllocateNamedDataSlot("userName"); 会报错,因为静态字典中已经存在了同名的数据槽

Username = Thread.AllocateNamedDataSlot("userName1");
Thread.SetData(Username, "Thread1"); Console.WriteLine($"Username1:{Thread.GetData(Username)}"); }); Thread thread2 = new Thread(() => { Username = Thread.AllocateNamedDataSlot("userName2"); Thread.SetData(Username, "Thread2"); Console.WriteLine($"Username2:{Thread.GetData(Username)}"); }); Thread thread3 = new Thread(() => { Username = Thread.AllocateNamedDataSlot("userName3"); Thread.SetData(Username, "Thread3"); Console.WriteLine($"Username3:{Thread.GetData(Username)}"); }); thread1.Start(); thread2.Start(); Console.WriteLine($"Username:{Thread.GetData(Username)}"); thread3.Start(); } } //输出结果: //Username:mainthread //Username:Thread1 //Username:Thread2 //Username:Thread3
复制代码

 

posted @ 2021-12-27 16:32  小林野夫  阅读(628)  评论(0)    收藏  举报
原文链接:https://www.cnblogs.com/cdaniu/