【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.AllocateNamedDataSlot 或 Thread.GetNamedDataSlot 方法。 若要获取对现有命名槽的引用,请将它的名称传递给 GetNamedDataSlot 方法。
若要创建未命名数据槽,请使用 Thread.AllocateDataSlot 方法。
对于命名槽和未命名槽,请使用 Thread.SetData 和 Thread.GetData 方法设置和检索槽中的信息。 这些静态方法始终处理当前正在执行它们的线程的数据。
命名槽非常便捷,因为可以在需要时检索槽,具体操作是将它的名称传递给 GetNamedDataSlot 方法,而不用维护对未命名槽的引用。 不过,如果另一个组件对线程相对存储使用相同的名称,并且线程同时执行你的组件和另一个组件的代码,这两个组件可能会相互损坏数据。 (此方案假定这两个组件都在同一个应用域中运行,并不旨在共享相同的数据。)
显然ThreadStatic特性只支持静态字段太受限制了,.NET线程类型中的LocalDataStoreSlot提供更好的TLS支持,但是性能不如上面介绍的ThreadStatic方法。注意:LocalDataStoreSlot有命名类型和非命名类型区分。
我们先来看看命名的LocalDataStoreSlot类型,可以通过Thread.AllocateNamedDataSlot来分配一个的空间,通过Thread.FreeNamedDataSlot来销毁一个的空间。
把线程相关的数据存储在LocalDataStoreSlot对象中,数据槽的获取和设置则通过Thread类型的GetData方法和SetData方法。
存放局部存储步骤:
1、申请数据槽
如果不存在名为para的数据槽,将分配一个所有线程均可用的para数据槽
2、往数据槽存放数据
para.I = i;
Thread.SetData(slot,para);
3、如有必要,释放数据槽
释放数据槽要小心,该操作将使所有线程存放在被释放的数据槽中的数据丢失。
读取局部存储步骤:
1、根据名字子线程局部存储中获取特定的数据槽
2、从数据槽获取数据
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的更多相关文章
- Entity Framework Context上下文管理(CallContext 数据槽)
Context上下文管理 Q1:脏数据 Q2:一次逻辑操作中,会多次访问数据库,增加了数据库服务器的压力 >在一次逻辑操作中实现上下文实例唯一 方法一:单例模式:内存的爆炸式增长 在整个运行期间 ...
- C# 如何保证对象线程内唯一:数据槽(CallContext)
如果说,一个对象保证全局唯一,大家肯定会想到一个经典的设计模式:单例模式,如果要使用的对象必须是线程内唯一的呢? 数据槽:CallContext,ok看下msdn对callcontent的解释. Ca ...
- C# 如何保证对象线程内唯一:数据槽(CallContext)【转载】
如果说,一个对象保证全局唯一,大家肯定会想到一个经典的设计模式:单例模式,如果要使用的对象必须是线程内唯一的呢? 数据槽:CallContext,ok看下msdn对callcontent的解释. Ca ...
- 如何保证对象线程内唯一:数据槽(CallContext)
CallContext 是类似于方法调用的线程本地存储区的专用集合对象,并提供对每个逻辑执行线程都唯一的数据槽.数据槽不在其他逻辑线程上的调用上下文之间共享.当 CallContext 沿执行代码路径 ...
- 第二节:深入剖析Thread的五大方法、数据槽、内存栅栏。
一. Thread及其五大方法 Thread是.Net最早的多线程处理方式,它出现在.Net1.0时代,虽然现在已逐渐被微软所抛弃,微软强烈推荐使用Task(后面章节介绍),但从多线程完整性的角度上来 ...
- CallContext线程数据缓存-调用上下文
一.CallContext 概述 命名空间:System.Runtime.Remoting.Messaging CallContext 用于提供与执行代码路径一起传送的属性集,直白讲就是:提供线程(多 ...
- java 线程数据同步
java 线程数据同步 由买票实例 //java线程实例 //线程数据同步 //卖票问题 //避免重复卖票 //线程 class xc1 implements Runnable{ //定义为静态,可以 ...
- WPF / Win Form:多线程去修改或访问UI线程数据的方法( winform 跨线程访问UI控件 )
WPF:谈谈各种多线程去修改或访问UI线程数据的方法http://www.cnblogs.com/mgen/archive/2012/03/10/2389509.html 子线程非法访问UI线程的数据 ...
- java 使用volatile实现线程数据的共享
java 使用volatile实现线程数据的共享 直接上代码看效果: public class VolatileTest extends Thread { private volatile boole ...
随机推荐
- cesium加载gltf模型点击以及列表点击定位弹窗
前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. 之 ...
- c#重写和多态
多态是基于重写的 继承:向子类中添加父类没有的成员,子类对父类的横向扩展 重写:纵向扩展,成员没有增加,但成员的版本增加了 引言 Rider JetBrains:Rider.ReSharper.dot ...
- es基础知识
1.ES定义 •是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储.检索数据:本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据 •使用Java开发并使用Lucene作为其核心来实现 ...
- golang中接口详解
package main import ( "fmt" ) type Sayer interface { say() } type Mover interface { move() ...
- python for循环while循环数据类型内置方法
while 条件: 条件成立之后循环执行的子代码块 每次执行完循环体子代码之后都会重新判断条件是否成立 如果成立则继续执行子代码如果不成立则退出 break用于结束本层循环 ### 一:continu ...
- Shell 脚本进阶,经典用法及其案例
一.条件选择.判断 1.条件选择if (1)用法格式 if 判断条件 1 ; then 条件为真的分支代码 elif 判断条件 2 ; then 条件为真的分支代码 elif 判断条件 3 ; the ...
- 分治FFT小记🐤
分治FFT:在 $O(n \log^2 n)$ 的时间内求出类似于 $f_i=\sum\limits_{j=0}^{i-1}g(i-j)f(j)$ 之类的递推式 思想:同 CDQ 分治的思想,先分成左 ...
- el表达式中的${param}用法
el表达式中的${param}? 1. 2. ${param.name} 等价于 request.getParamter("name"),这两种方法一般用于服务器从页面或者客户端获 ...
- STS中创建 javaweb 项目?
package com.aaa.readme; /* * 一. * 1.安装Tomcat 版本8.5 * * 2.file---->new------>dynamic java web p ...
- iBooker 财务提升星球 2020.2~3 热门讨论
前两天分享了一下关于我们个人的现金流,今天就以公司的角度去分- 我们技术人,如何开源增加我们的收入? 首先,我们对收入进行下- 热门股要不要买? 参考标准: 1. 时机 2. 泡沫 时- #老实人报# ...