.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 模式:即使只有一个入口,内部也会为每个线程分配特有的存储空间,线程间 没有共享资源 ...
随机推荐
- Oracle数据库之开发PL/SQL子程序和包
Oracle数据库之开发PL/SQL子程序和包 PL/SQL块分为匿名块与命名块,命名块又包含子程序.包和触发器. 过程和函数统称为PL/SQL子程序,我们可以将商业逻辑.企业规则写成过程或函数保 ...
- Win7安装和配置Tigase 5.2server
Win7安装和配置Tigaseserver 笔者:chszs,转载注明. 博客首页:http://blog.csdn.net/chszs 1.下载tigase-server-5.2.0-b3447.e ...
- C#/.NET code
Some practices to write better C#/.NET code(译) C#(.NET)中有关编码的一些建议,原文地址:http://www.codeproject.com/Ar ...
- ORACLE union order by
select * from ( select a.id,a.oacode,a.custid,a.custname,a.xsz,a.salename,a.communicationtheme,a.com ...
- 【机器学习算法-python实现】KNN-k近邻算法的实现(附源代码)
,400],[200,5],[100,77],[40,300]]) shape:显示(行,列)例:shape(group)=(4,2) zeros:列出一个同样格式的空矩阵,例:zeros(group ...
- VTune使用amplxe-cl进行Hardware Event-based Sampling Analysis 0分析
于BASH正在使用VTune进行Hardware Event-based Sampling Analysis 0分析: 结果(部分)例如以下: 版权声明:本文博客原创文章.博客,未经同意,不得转载.
- Oracle OS认证和口令文件认证方法
OS认证 1.在SQLNET.ORA(位于$ORACLE_HOME/NETWORK/ADMIN文件夹中)文件里,使用vi编辑,凝视掉#SQLNET.AUTHENTICATION_SERVICES = ...
- The Swift Programming Language-官方教程精译Swift(3)基本运算符
运算符是检查, 改变, 合并值的特殊符号或短语. 例如, 加号 + 把计算两个数的和(如 let i = 1 + 2). 复杂些的运行算包括逻辑与&&(如 if enteredDoor ...
- 伺服驱动器UVW电机电源线相序错误
我们有必要先了解此讨论的前提:编码器初始安装相位正确.伺服驱动器将全然"採信"电机编码器的初始安装相位所表征的电机电角度相位,无需在伺服电机 的UVW动力线接线连接后进行额外 ...
- 第4章3节《MonkeyRunner源码剖析》ADB协议及服务: ADB协议概览SYNC.TXT翻译参考(原创)
天地会珠海分舵注:本来这一系列是准备出一本书的,详情请见早前博文“寻求合作伙伴编写<深入理解 MonkeyRunner>书籍“.但因为诸多原因,没有如愿.所以这里把草稿分享出来,所以错误在 ...