背景

为了确保在线程中声明特定类型的变量,在每个线程中的值都是唯一的,不受到其他线程对该变量读写的影响。也就是俗称的线程本地存储 (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

【C# 线程】数据槽 LocalDataStoreSlot简称DataSlot的更多相关文章

  1. Entity Framework Context上下文管理(CallContext 数据槽)

    Context上下文管理 Q1:脏数据 Q2:一次逻辑操作中,会多次访问数据库,增加了数据库服务器的压力 >在一次逻辑操作中实现上下文实例唯一 方法一:单例模式:内存的爆炸式增长 在整个运行期间 ...

  2. C# 如何保证对象线程内唯一:数据槽(CallContext)

    如果说,一个对象保证全局唯一,大家肯定会想到一个经典的设计模式:单例模式,如果要使用的对象必须是线程内唯一的呢? 数据槽:CallContext,ok看下msdn对callcontent的解释. Ca ...

  3. C# 如何保证对象线程内唯一:数据槽(CallContext)【转载】

    如果说,一个对象保证全局唯一,大家肯定会想到一个经典的设计模式:单例模式,如果要使用的对象必须是线程内唯一的呢? 数据槽:CallContext,ok看下msdn对callcontent的解释. Ca ...

  4. 如何保证对象线程内唯一:数据槽(CallContext)

    CallContext 是类似于方法调用的线程本地存储区的专用集合对象,并提供对每个逻辑执行线程都唯一的数据槽.数据槽不在其他逻辑线程上的调用上下文之间共享.当 CallContext 沿执行代码路径 ...

  5. 第二节:深入剖析Thread的五大方法、数据槽、内存栅栏。

    一. Thread及其五大方法 Thread是.Net最早的多线程处理方式,它出现在.Net1.0时代,虽然现在已逐渐被微软所抛弃,微软强烈推荐使用Task(后面章节介绍),但从多线程完整性的角度上来 ...

  6. CallContext线程数据缓存-调用上下文

    一.CallContext 概述 命名空间:System.Runtime.Remoting.Messaging CallContext 用于提供与执行代码路径一起传送的属性集,直白讲就是:提供线程(多 ...

  7. java 线程数据同步

    java 线程数据同步 由买票实例 //java线程实例 //线程数据同步 //卖票问题 //避免重复卖票 //线程 class xc1 implements Runnable{ //定义为静态,可以 ...

  8. WPF / Win Form:多线程去修改或访问UI线程数据的方法( winform 跨线程访问UI控件 )

    WPF:谈谈各种多线程去修改或访问UI线程数据的方法http://www.cnblogs.com/mgen/archive/2012/03/10/2389509.html 子线程非法访问UI线程的数据 ...

  9. java 使用volatile实现线程数据的共享

    java 使用volatile实现线程数据的共享 直接上代码看效果: public class VolatileTest extends Thread { private volatile boole ...

随机推荐

  1. WSL删除子系统后无法重装

    问题 WSL卸载后安装error 解决办法 UWP应用卸载后没有删除目录下的文件 C:\Users\wwwfe\AppData\Local\Packages路径下删除就可以了 再次安装会卡顿很久,可能 ...

  2. 安卓无法访问Azure服务器和微软API

    Azure服务器保护机制限制移动端访问 必须使用移动app服务来转接api,才可以访问.

  3. 【转载】ASP.NET前台代码绑定

    ASP.NET前台代码绑定后台变量方法总结http://www.cnblogs.com/lerit/archive/2010/10/22/1858007.html ASP.NET前台无法访问后台int ...

  4. 短视频正当时,如何让你的App快速构建视频创作能力?

    视频编辑服务(Video Editor Kit)是华为开放给开发者快速构建视频编辑能力的服务,提供视频导入.编辑处理.特效渲染.视频导出.媒体资源管理等一站式视频处理能力.视频编辑服务为全球开发者提供 ...

  5. 【程序5】输入三个整数x,y,z,请把这三个数由小到大输出

    我自己写的: x = int(input('x:')) y = int(input('y:')) z = int(input('z:')) L = [x,y,z] print(sorted(L)) 官 ...

  6. Typora下载安装教程(全面)

    Typora下载与安装 一:下载 1.1百度搜索 https://www.typora.io/ 点击链接进入后映入眼帘的就是一款简洁的Typora网页,然后下滑进入主页. 1.2点击Download( ...

  7. 张高兴的 .NET IoT 入门指南:(七)制作一个气象站

    距离上一篇<张高兴的 .NET Core IoT 入门指南>系列博客的发布已经过去 2 年的时间了,2 年的时间 .NET 版本发生了巨大的变化,.NET Core 也已不复存在,因此本系 ...

  8. Swift逻辑分支

    一. 分支的介绍 分支即if/switch/三目运算符等判断语句 通过分支语句可以控制程序的执行流程 二. if分支语句 和OC中if语句有一定的区别 判断句可以不加() 在Swift的判断句中必须有 ...

  9. element-ui 使用 Select 组件给 value 属性绑定对象类型

    qq_36437172 2020-06-28 22:38:49  778  收藏 分类专栏: element-ui 文章标签: element-ui Select 组件 value 属性 绑定 对象类 ...

  10. SQL 游标 指针

    DECLARE @radioScoreRate decimal DECLARE @checkScoreRate decimal DECLARE @judgeScoreRate decimal DECL ...