.NET:线程本地存储、调用上下文、逻辑调用上下文
.NET:线程本地存储、调用上下文、逻辑调用上下文
背景返回目录
在多线程环境,如果需要将实例的生命周期控制在某个操作的执行期间,该如何设计?经典的思路是这样的:作为参数向调用栈传递,如:CommandExecuteContext、HttpContext等。好在很多平台都提供线程本地存储这种东西,下面介绍一下 .NET 提供的三种机制。
线程本地存储返回目录
代码

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7 using System.Runtime.Remoting;
8
9 namespace ExecutionContextStudy
10 {
11 class ThreadDataSlotTest
12 {
13 public static void Test()
14 {
15 for (var i = 0; i < 10; i++)
16 {
17 Thread.Sleep(10);
18
19 Task.Run(() =>
20 {
21 var slot = Thread.GetNamedDataSlot("test");
22 if (slot == null)
23 {
24 Thread.AllocateNamedDataSlot("test");
25 }
26
27 if (Thread.GetData(slot) == null)
28 {
29 Thread.SetData(slot, DateTime.Now.Millisecond);
30 }
31
32 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + Thread.GetData(slot));
33 });
34 }
35
36 Console.ReadLine();
37 }
38 }
39 }

结果

说明
如果使用了线程池,最好不要使用这种存储机制了,因为线程池可能不会释放使用过的线程,导致多次执行之间可能共享数据(可以每次执行前重置线程本地存储的数据)。
调用上下文返回目录
代码

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7 using System.Runtime.Remoting.Messaging;
8
9 namespace ExecutionContextStudy
10 {
11 class CallContextTest
12 {
13 public static void Test()
14 {
15 Console.WriteLine("测试:CallContext.SetData");
16 for (var i = 0; i < 10; i++)
17 {
18 Thread.Sleep(10);
19
20 Task.Run(() =>
21 {
22 if (CallContext.GetData("test") == null)
23 {
24 CallContext.SetData("test", DateTime.Now.Millisecond);
25 }
26
27 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));
28 });
29 }
30
31 Console.ReadLine();
32 }
33 }
34 }

结果

说明
由上图可以知道,每次执行的数据是完全隔离的,非常符合我们的期望。但是,如果我们期望调用期间又开启了一个子线程,如何让子线程访问父线程的数据呢?这就需要使用到:“逻辑调用上下文”。
逻辑调用上下文返回目录
代码

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7 using System.Runtime.Remoting.Messaging;
8
9 namespace ExecutionContextStudy
10 {
11 class ExecutionContextTest
12 {
13 public static void Test()
14 {
15 Console.WriteLine("测试:CallContext.SetData");
16 Task.Run(() =>
17 {
18 CallContext.SetData("test", "段光伟");
19 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));
20
21 Task.Run(() =>
22 {
23 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));
24 });
25 });
26
27 Thread.Sleep(100);
28
29 Console.WriteLine("测试:CallContext.LogicalSetData");
30 Task.Run(() =>
31 {
32 CallContext.LogicalSetData("test", "段光伟");
33 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.LogicalGetData("test"));
34
35 Task.Run(() =>
36 {
37 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.LogicalGetData("test"));
38 });
39
40 ExecutionContext.SuppressFlow();
41 Task.Run(() =>
42 {
43 Console.WriteLine("SuppressFlow 之后:" + CallContext.LogicalGetData("test"));
44 });
45
46 ExecutionContext.RestoreFlow();
47 Task.Run(() =>
48 {
49 Console.WriteLine("RestoreFlow 之后:" + CallContext.LogicalGetData("test"));
50 });
51 });
52
53 Console.ReadLine();
54 }
55 }
56 }

输出

说明
注意 ExecutionContext.SuppressFlow(); 和 xecutionContext.RestoreFlow();,它们分别能阻止传播和重置传播,默认是允许传播的。
备注返回目录
最常见的使用场景就是:为 Ioc 容器自定义生命周期管理模型。
.NET:线程本地存储、调用上下文、逻辑调用上下文的更多相关文章
- C# 线程本地存储 调用上下文 逻辑调用上下文
线程本地存储 using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleAppTest ...
- 线程本地存储 ThreadLocal
线程本地存储 · 语雀 (yuque.com) 线程本地存储提供了线程内存储变量的能力,这些变量是线程私有的. 线程本地存储一般用在跨类.跨方法的传递一些值. 线程本地存储也是解决特定场景下线程安全问 ...
- 线程本地存储TLS(Thread Local Storage)的原理和实现——分类和原理
原文链接地址:http://www.cppblog.com/Tim/archive/2012/07/04/181018.html 本文为线程本地存储TLS系列之分类和原理. 一.TLS简述和分类 我们 ...
- 线程本地存储TLS(Thread Local Storage)的原理和实现——分类和原理
本文为线程本地存储TLS系列之分类和原理. 一.TLS简述和分类 我们知道在一个进程中,所有线程是共享同一个地址空间的.所以,如果一个变量是全局的或者是静态的,那么所有线程访问的是同一份,如果某一个线 ...
- ThreadLocal(线程本地存储)
1. ThreadLocal,即线程本地变量或线程本地存储. threadlocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的 ...
- 线程本地存储(动态TLS和静态TLS)
线程本地存储(TLS) 对于多线程应用程序,如果线程过于依赖全局变量和静态局部变量就会产生线程安全问题.也就是一个线程的使用全局变量可能会影响到其他也使用此全局变量的线程,有可能会造成一定的错误,这可 ...
- Atitit usrqbg1821 Tls 线程本地存储(ThreadLocal Storage 规范标准化草案解决方案ThreadStatic
Atitit usrqbg1821 Tls 线程本地存储(ThreadLocal Storage 规范标准化草案解决方案ThreadStatic 1.1. ThreadLocal 设计模式1 1.2. ...
- 线程本地存储(Thread Local Storage, TLS)简单分析与使用
在多线程编程中, 同一个变量, 如果要让多个线程共享访问, 那么这个变量可以使用关键字volatile进行声明; 那么如果一个变量不想使多个线程共享访问, 那么该怎么办呢? 呵呵, 这个办法就是TLS ...
- Java线程本地存储ThreadLocal
前言 ThreadLocal 是一种 无同步 的线程安全实现 体现了 Thread-Specific Storage 模式:即使只有一个入口,内部也会为每个线程分配特有的存储空间,线程间 没有共享资源 ...
随机推荐
- thinkphp学习笔记2—入口文件
原文:thinkphp学习笔记2-入口文件 在thinkphp中有两个入口文件,一个是项目的入口文件,是index.php在主目录里面,还有一个是thinkphp框架的的入口文件,放在框架目录下面如: ...
- android账号与同步之发起同步
上一篇博文我介绍了账号与同步的同步实现过程,当中提供了一个工系统进程调用的服务,那么这个服务究竟是怎么被启动和使用的呢?这篇博文我就大体梳理一下启动过程. 事实上作为一个一般开发者,我们仅仅要知道要想 ...
- Oracle安装及使用入门
新手Oracle安装及使用入门 一.安装Oracle Step1 下载oracle压缩包并解压到同一文件夹下面 Step2 双击setup.exe进行安装 Step3:进入如下界面配置: 邮箱可不 ...
- RQNOJ PID2 / 开心的金明
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N 元钱就行”.今 ...
- 建立TextView位置的部分可以点击,不同的颜色
String url="注册代表宝藏驱动器,你已经允许成员<服务条款>,请仔细阅读. "; SpannableStringBuilder style = new Spa ...
- Uva 409-Excuses, Excuses!(串)
Judge Ito is having a problem with people subpoenaed for jury duty giving rather lame excuses in ord ...
- 导出DBF,并且提供下载 .
原文:导出DBF,并且提供下载 . 导出DBF,并且提供下载 #region Declare string mFilePath = MapPath("../DataTmp/"); ...
- nexus私服linux搭建问题
一.最近搭建nexus私服,从官网下载下来总是报503服务器无效,很是无奈,最后在网上找到一个可以用的 收藏起来,这里给大家共享一下 下载地址:http://pan.baidu.com/s/1kT3U ...
- CentOs Linux 常见命令
整理一些常用的命令(持续更新): 查看端口是否开启: netstat -an | grep prot (查看是否打开23端口) |:通道的意思,grep是指查看当前字符所在的行 LINUX通过下面的命 ...
- jmeter之GUI运行原理
一.一语道破jmeter 大家都知道我们在应用jmeter的图形化界面来进行操作,保存后生成的是一个.jmx文件. 那么这个.jmx文件中都是些什么呢. <?xml ve ...