背景

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

    .Action概述 ES提供client供集群节点或java客户端访问集群用.client模块通过代理模式,将所有的操作都集成到client接口中.这样外部调用只需要初始化client就能够完成所有的 ...

  2. BUGKU-Misc 成果狗成果狗

    下载下来可以得到一张图片 成果真好看 放到kali里面用binwalk查看有没有隐藏文件,发现这里面有两张图片 然后可以拖到winhex或者010里面把两张图片分离出来,可以分离出1.jpg和54.j ...

  3. cygwin -- 在windows平台上运行的unix模拟环境

    cygwin是一个在windows平台上运行的unix模拟环境,是cygnus solutions公司开发的自由软件(该公司开发了很多好东西,著名的还有eCos,不过现已被Redhat收购).它对于学 ...

  4. Java 锁 概念介绍

    一   Java中的锁是什么? /* * 一 Java锁定义? * 在计算机科学中,锁(lock)或互斥(mutex)是一种同步机制,用于在有许多执行线程的环境中强制对资源的访问限制. * 锁旨在强制 ...

  5. ARC-124 部分题解

    E 直接统计原式不好做,注意到首先我们应该知道怎样的 \(x\) 序列是合法的,那么不妨首先来统计一下合法的 \(x\) 序列数量. 令 \(b_i\) 为 \(i\) 向右给的球数,那么有(\(i ...

  6. 解决 413 Request Entity Too Large

    修改配置文件  vim /etc/nginx/sites-available/default,增加 client_max_body_size 1000m;//最大上传大小 proxy_connect_ ...

  7. 解决死锁之路3 - 常见 SQL 语句的加锁分析 (转)

    出处:https://www.aneasystone.com/archives/2017/12/solving-dead-locks-three.html 这篇博客将对一些常见的 SQL 语句进行加锁 ...

  8. ArrayList和LinkList的区别

    底层实现区别 ArrayList 底层实现就是数组,且ArrayList实现了RandomAccess,表示它能快速随机访问存储的元素,通过下标 index 访问,只是我们需要用 get() 方法的形 ...

  9. Java微信公众号服务器配置-验证Token

    一.填写服务器配置 首先我们需要在微信公众平台上填写服务器配置 重点内容    服务器地址URL(一定要外网能访问的到)        在我们提交配置的时候,微信会发送GET请求到URL上,      ...

  10. iptables防火墙 (纸是包不住火的,得用水泥)

    iptables防火墙 1.Linux防火墙基础 2.编写防火墙规则 1.Linux防火墙基础 iptables概述: Linux 系统的防火墙: IP信息包过滤系统,它实际上由两个组件netfilt ...